今天就跟大家聊聊有關利用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對象注入順序的問題有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。