springboot2.x解决运行顺序及Bean对象注入顺序的问题

网友投稿 269 2023-02-10

springboot2.x解决运行顺序及Bean对象注入顺序的问题

1 前言

通过指定接口,重写指定方法,可以在Bean对应的生命周期方法中执行相应的程序

2 测试

本文将分析几个Bean对象,为它们设置优先级(通过@Order),然后再打断点调试,测试各种生命周期方法的运行的顺序

在项目当中最让人头疼的就是bean对象不被注入的问题,通过本文,你可以很好的解决这个问题。

先看看本程序使用的依赖

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

2.3.0.RELEASE

com.wu

smartport

0.0.1-SNAPSHOT

Demo project for Spring Boot

1.8

org.springframework.boot

spring-boot-starter

org.projectlombok

lombok

true

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-maven-plugin

org.projectlombok

lombok

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

2.3.0.RELEASE

com.wu

smartport

0.0.1-SNAPSHOT

Demo project for Spring Boot

1.8

org.springframework.boot

spring-boot-starter

org.projectlombok

lombok

true

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-maven-plugin

org.projectlombok

lombok

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

*/

@OverrizPjsvMde

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获取对象,然后把对象重新注入进去。

销毁的顺序

3 @Dependon 和 @Order

@Dependon 和@Order 共同决定Bean对象的注入顺序,

如果A对象 @Dependon B对象,则无论A对象和B对象的@Order的值是什么,都以@Dependon标签为主

例如A对象@Dependon(“b”),@Order(1) ,B对象@Order(15),则B对象将先于A对象注入spring容器中

4 利用BeanFactoryPostProcessor 初始化

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 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 inits = new TreeSet<>(Comparator.comparingInt(ObserverForInit::getInitOrder));

@Override

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

Iterator 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 arr;

try{

// 尝试从容器中获取代码块

Object bean = beanFactory.getBean("function");

arr = (ArrayList)bean;

}catch (Exception e2){

// 如果不存在则创建代码块

arr = new ArrayList<>();

}

// 书写一段代码

Function 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 arr = (ArrayList) bean;

for (int i = 0; i < arr.size(); i++) {

//如果有,则执行该方法。

Function f = arr.get(i);

f.apply(null);

}

}catch (Exception e){

e.printStackTrace();

}

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:智能聚合页不显示快递信息(智能聚合页不显示快递信息怎么办)
下一篇:微信小程序能用聚合数据(微信小程序接入聚合支付)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~