今天就跟大家聊聊有关利用springboot2.x怎么解决Bean对象注入顺序的问题,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
通过指定接口,重写指定方法,可以在Bean对应的生命周期方法中执行相应的程序
本文将分析几个Bean对象,为它们设置优先级(通过@Order),然后再打断点调试,测试各种生命周期方法的运行的顺序
在项目当中最让人头疼的就是bean对象不被注入的问题,通过本文,你可以很好的解决这个问题。
先看看本程序使用的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wu</groupId>
<artifactId>smartport</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>smartport</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.1 Order = 1
package com.wu.smartport.controller;
import com.wu.smartport.test.User;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(1)
public class TestController implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanDefinitionRegistryPostProcessor, InitializingBean, DisposableBean {
@Autowired
private User user;
/**
* 最先执行,需要接口BeanNameAware
*
* @param name
*/
@Override
public void setBeanName(String name) {
// 获取到的是testController,即注入进Spring中的名称
System.out.println("setBeanName:" + name);
}
/**
* 第2个执行,需要接口BeanFactoryAware
* beanFactory可以获取其他已注入的Bean对象,但无法注入其他对象
*
* @param beanFactory
* @throws BeansException
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
}
/**
* 第3个执行,需要ApplicationContextAware接口
* 可以获取到上下文对象applicationContext,允许容器通过应用程序上下文环境创建、获取、管理bean
*
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// 可以通过上下文对象获取工厂并注入对象
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
/**
* 第4个执行,依赖于InitializingBean接口
*
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
}
/**
* 第5个执行,依赖于BeanDefinitionRegistryPostProcessor接口
* 当完成本方法后,对象就会完成注入
* @param registry
* @throws BeansException
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
}
/**
* 第6个执行,来源于BeanFactoryPostProcessor接口,该接口被BeanDefinitionRegistryPostProcessor接口实现了。
* 一般的Bean对象在此方法前都被注入到了容器中,如果本对象没有获取到,则可以在这里获取。
* @param beanFactory
* @throws BeansException
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Object user = beanFactory.getBean("user");
}
/**
* 第7个执行,本方法将被多次执行,依赖于BeanPostProcessor接口
* 每注入一个对象的时候,都会调用该方法
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return null;
}
/**
* 第8个执行,本方法将被多次执行,依赖于BeanPostProcessor接口
* 每注入一个对象之后,都会调用该方法
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return null;
}
/**
* 在本对象被销毁后执行,依赖于DisposableBean接口
* @throws Exception
*/
@Override
public void destroy() throws Exception {
}
}
2.2 Order = 15
package com.wu.smartport.test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
/**
* @Author :吴用
* @Date :2021-01-05 8:40
* @Version :1.0
*/
@Service
@Order(15)
public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanDefinitionRegistryPostProcessor, InitializingBean, DisposableBean {
@Value("张三")
private String name;
@Value("12")
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* 最先执行,需要接口BeanNameAware
*
* @param name
*/
@Override
public void setBeanName(String name) {
System.out.println("setBeanName:" + name);
}
/**
* 第2个执行,需要接口BeanFactoryAware
* beanFactory可以获取其他已注入的Bean对象,但无法注入其他对象
*
* @param beanFactory
* @throws BeansException
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
}
/**
* 第3个执行,需要ApplicationContextAware接口
* 可以获取到上下文对象applicationContext,允许容器通过应用程序上下文环境创建、获取、管理bean
*
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
}
/**
* 第4个执行,依赖于InitializingBean接口
*
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
}
/**
* 第5个执行,依赖于BeanDefinitionRegistryPostProcessor接口
* 当完成本方法后,对象就会完成注入
* @param registry
* @throws BeansException
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
}
/**
* 第6个执行,来源于BeanFactoryPostProcessor接口,该接口被BeanDefinitionRegistryPostProcessor接口实现了。
* 一般的Bean对象在此方法前都被注入到了容器中,如果本对象没有获取到,则可以在这里获取。
* @param beanFactory
* @throws BeansException
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Object user = beanFactory.getBean("user");
}
/**
* 第7个执行,本方法将被多次执行,依赖于BeanPostProcessor接口
* 每注入一个对象的时候,都会调用该方法
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return null;
}
/**
* 第8个执行,本方法将被多次执行,依赖于BeanPostProcessor接口
* 每注入一个对象之后,都会调用该方法
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return null;
}
/**
* 在本对象被销毁后执行,依赖于DisposableBean接口
* @throws Exception
*/
@Override
public void destroy() throws Exception {
}
}
2.3 Order = 30
package com.wu.smartport.test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @Author :吴用
* @Date :2021-01-05 9:48
* @Version :1.0
*/
@Order(30)
@Component
public class User2 implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanDefinitionRegistryPostProcessor, InitializingBean, DisposableBean {
@Value("张三")
private String name;
@Value("12")
private int age;
public User2() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* 最先执行,需要接口BeanNameAware
*
* @param name
*/
@Override
public void setBeanName(String name) {
System.out.println("setBeanName:" + name);
}
/**
* 第2个执行,需要接口BeanFactoryAware
* beanFactory可以获取其他已注入的Bean对象,但无法注入其他对象
*
* @param beanFactory
* @throws BeansException
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
}
/**
* 第3个执行,需要ApplicationContextAware接口
* 可以获取到上下文对象applicationContext,允许容器通过应用程序上下文环境创建、获取、管理bean
*
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
}
/**
* 第4个执行,依赖于InitializingBean接口
*
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
}
/**
* 第5个执行,依赖于BeanDefinitionRegistryPostProcessor接口
* 当完成本方法后,对象就会完成注入
* @param registry
* @throws BeansException
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
}
/**
* 第6个执行,来源于BeanFactoryPostProcessor接口,该接口被BeanDefinitionRegistryPostProcessor接口实现了。
* 一般的Bean对象在此方法前都被注入到了容器中,如果本对象没有获取到,则可以在这里获取。
* @param beanFactory
* @throws BeansException
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Object user = beanFactory.getBean("user");
}
/**
* 第7个执行,本方法将被多次执行,依赖于BeanPostProcessor接口
* 每注入一个对象的时候,都会调用该方法
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return null;
}
/**
* 第8个执行,本方法将被多次执行,依赖于BeanPostProcessor接口
* 每注入一个对象之后,都会调用该方法
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return null;
}
/**
* 在本对象被销毁后执行,依赖于DisposableBean接口
* @throws Exception
*/
@Override
public void destroy() throws Exception {
}
}
2.4 实验结果
如下图所示
TestController 的Order=1,最高优先级
User 的 Order = 15,中等优先级
User2 的 Order = 30,低优先级
前四个方法会按照优先级的顺序先后执行,然后按优先级顺序执行postProcessBeanDefinitionRegistry方法,然后再按优先级顺序执行postProcessBeanFactory方法
postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 方法很不错,给了beanFactory。不仅如此,在此方法以前,所有的Bean对象已经被注入完毕了,所以如果之前你的对象没有注入进去,你就可以在这里通过beanFactroy获取对象,然后把对象重新注入进去。
销毁的顺序
@Dependon 和@Order 共同决定Bean对象的注入顺序,
如果A对象 @Dependon B对象,则无论A对象和B对象的@Order的值是什么,都以@Dependon标签为主
例如A对象@Dependon(“b”),@Order(1) ,B对象@Order(15),则B对象将先于A对象注入spring容器中
4.1 一般初始化
根据上面的实验我们知道实现BeanFactoryPostProcessor接口后,重写void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
在该方法运行时,所有的bean对象都已经被注入到了spring容器中,此时可以利用观察者模式将你需要初始化的对象进行初始化。
首先,需要写一个ObserverForInit接口
package com.wu.smartport.controller;
/**
* 观察者,用于初始化
* @Author :吴用
* @Date :2021-01-05 11:02
* @Version :1.0
*/
public interface ObserverForInit {
/**
* 观察者初始化
*/
void observerInit();
}
再让需要初始化操作的bean对象实现该接口
package com.wu.smartport.test;
import com.wu.smartport.controller.ObserverForInit;
import org.springframework.stereotype.Component;
/**
* @Author :吴用
* @Date :2021-01-05 11:11
* @Version :1.0
*/
@Component
public class User implements ObserverForInit {
@Override
public void observerInit() {
System.out.println("我要进行初始化了!");
}
}
然后再写一个管理bean初始化的类 通过遍历所有的Bean对象,然后查询指定的接口或者自定义注解,执行相应的操作(比如初始化操作。)
package com.wu.smartport.manager;
import com.wu.smartport.controller.ObserverForInit;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.util.Iterator;
/**
* @Author :吴用
* @Date :2021-01-05 11:06
* @Version :1.0
*/
@Component
public class ControllerInitManager implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Iterator<String> its = beanFactory.getBeanNamesIterator();
while (its.hasNext()) {
String beanName = its.next();
try {
Object bean = beanFactory.getBean(beanName);
analysisObject(bean);
} catch (BeanCreationException e) {
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 分析bean对象
*
* @param bean
*/
private void analysisObject(Object bean) {
analysisInterface(bean);
analysisAnnotation(bean);
}
/**
* 分析接口
*
* @param bean
*/
private void analysisInterface(Object bean) {
Class<?> beanClass = bean.getClass();
// 分析Interface 和 Annotation
Class<?>[] interfaces = beanClass.getInterfaces();
// 分析Class
for (Class infs : interfaces) {
if (infs.equals(ObserverForInit.class)) {
((ObserverForInit) bean).observerInit();
}
}
}
/**
* 分析注解
*
* @param bean
*/
private void analysisAnnotation(Object bean) {
}
}
4.2 按序初始化
如果对初始化的顺序有自己要求,可以采取如下的方法。至于4.1中的遍历顺序,读者可以自行研究,但建议自己写顺序,否则一旦springboot框架内部有变,咱们程序内部的初始顺序可能会出问题。
设置一个TreeSet 并给定排序策略,遍历接口的时候,先将找到的对象放入TreeSet中排序,再遍历完成之后再执行相应的操作
修改后的接口
package com.wu.smartport.controller;
/**
* 观察者,用于初始化
* @Author :吴用
* @Date :2021-01-05 11:02
* @Version :1.0
*/
public interface ObserverForInit {
/**
* 观察者初始化
*/
void observerInit();
/**
* 初始化的顺序,数越小,优先级越高
* @return
*/
int getInitOrder();
}
bean对象
/**
* @Author :吴用
* @Date :2021-01-04 22:51
* @Version :1.0
*/
@Component
public class PageManager implements ObserverForInit {
@Override
public void observerInit() {
System.out.println("PageManager初始化");
}
@Override
public int getInitOrder() {
return 1000;
}
}
管理初始化的类
package com.wu.smartport.manager;
import com.wu.smartport.controller.ObserverForInit;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/**
* @Author :吴用
* @Date :2021-01-05 11:06
* @Version :1.0
*/
@Component
public class ControllerInitManager implements BeanFactoryPostProcessor {
private TreeSet<ObserverForInit> inits = new TreeSet<>(Comparator.comparingInt(ObserverForInit::getInitOrder));
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Iterator<String> its = beanFactory.getBeanNamesIterator();
while (its.hasNext()) {
String beanName = its.next();
try {
Object bean = beanFactory.getBean(beanName);
analysisObject(bean);
} catch (BeanCreationException e) {
} catch (Exception e) {
e.printStackTrace();
}
}
// 遍历完成后的操作
analysisByAfterIterator();
}
/**
* 分析bean对象
*
* @param bean
*/
private void analysisObject(Object bean) {
analysisInterface(bean);
analysisAnnotation(bean);
}
/**
* 遍历之后的操作
*/
private void analysisByAfterIterator() {
// 按照指定的顺序遍历
// 升序遍历,order小的先执行初始化方法
for (ObserverForInit o : inits) {
o.observerInit();
}
}
/**
* 分析接口
*
* @param bean
*/
private void analysisInterface(Object bean) {
Class<?> beanClass = bean.getClass();
// 分析Interface 和 Annotation
Class<?>[] interfaces = beanClass.getInterfaces();
// 分析Class
for (Class infs : interfaces) {
if (infs.equals(ObserverForInit.class)) {
inits.add((ObserverForInit) bean);
}
}
}
/**
* 分析注解
*
* @param bean
*/
private void analysisAnnotation(Object bean) {
}
}
5 基于 Springboot 实现冯诺依曼结构
下面讲解一个骚操作
冯诺依曼结构:将程序和数据分别存储在内存当中
基于这种思想,我们不光可以把数据存储在容器当中,我们还可以把代码也存储在springboot容器当中。
创建一个Bean对象,实现BeanFactoryPostProcessor接口,在运行到该方法的时候,大部分的对象已经被装入了spring容器中。你可以在之后必要的地方从spring容器中提取该代码执行。
package com.wu.smartport.test;
import com.wu.smartport.SmartportApplication;
import javafx.stage.Stage;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.function.Function;
import static com.wu.smartport.config.BeanInitOrder.INIT_METHODS;
import static com.wu.smartport.config.BeanInitOrder.STAGE_BEAN;
/**
* @Author :吴用
* @Date :2021-01-05 19:27
* @Version :1.0
*/
public class Manager implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 执行方法告诉javaFx
ArrayList<Function> arr;
try{
// 尝试从容器中获取代码块
Object bean = beanFactory.getBean("function");
arr = (ArrayList<Function>)bean;
}catch (Exception e2){
// 如果不存在则创建代码块
arr = new ArrayList<>();
}
// 书写一段代码
Function<Void,Void> f = aVoid -> {
// 相关的业务
return null;
};
arr.add(f);
// 将代码块注入到spring容器中
DefaultListableBeanFactory factory = (DefaultListableBeanFactory)beanFactory;
factory.registerSingleton(INIT_METHODS,arr);
}
}
在之后一定会运行到的代码,比如启动类之后,可以执行指定的代码段。
package com.wu.smartport;
import javafx.application.Application;
import javafx.stage.Stage;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.ArrayList;
import java.util.function.Function;
import static com.wu.smartport.config.BeanInitOrder.INIT_METHODS;
import static com.wu.smartport.config.BeanInitOrder.STAGE_BEAN;
/**
* 主启动类
* @author Wu_Sir
*/
@SpringBootApplication
public class SmartportApplication{
private static volatile ConfigurableApplicationContext run;
/**
* 主程序入口
*
* @param args
*/
public static void main(String[] args) {
run = SpringApplication.run(SmartportApplication.class, args);
// 查看是否有要处理的方法
try{
Object bean = beanFactory.getBean("function");
ArrayList<Function> arr = (ArrayList<Function>) bean;
for (int i = 0; i < arr.size(); i++) {
//如果有,则执行该方法。
Function f = arr.get(i);
f.apply(null);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
看完上述内容,你们对利用springboot2.x怎么解决Bean对象注入顺序的问题有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。