1 前言
通过指定接口,重写指定方法,可以在Bean对应的生命周期方法中执行相应的程序 在项目当中最让人头疼的就是bean对象不被注入的问题,通过本文,你可以很好的解决这个问题。
2 测试
本文将分析几个Bean对象,为它们设置优先级(通过@Order),然后再打断点调试,测试各种生命周期方法的运行的顺序 本文中将测试以下几个spring提供的接口(对Bean对象使用,下面几个接口提供的方法是有先后运行顺序的,对于单个Bean而言。运行的顺序和我这里给出的接口的顺序一致。)
BeanNameAware BeanFactoryAware ApplicationContextAware InitializingBean BeanDefinitionRegistryPostProcessor,BeanFactoryPostProcessor,前者实现了后者。
使用这两个接口时要注意,经测试,只要bean对象继承这两个其中的任意一个接口,都会导致Bean对象内部的@Autowired等注入方法失效。即便使用@Order设置优先级和使用@Dependon设置依赖,也不能让bean对象注入到成员变量中 但是这两个接口提供了两个形参含有BeanFactory的方法,并且这两个方法是在所有bean对象被注入spring后(正常方式,不包括随后手动注入的)才会调用的,所以你可以在这两个方法内部手动提取Bean对象。 也就是说,只要你的Bean对象实现了该接口,spring就会认为你是要自己去提取bean对象,于是就不帮你自动注入了。 被@Autowired 注释的Bean对象实现这个接口后,依然能被自动注入。例如MainController 中需要注入MainService,在MainService上标记@Autowied。而MainService实现了BeanDefinitionRegistryPostProcessor接口,但MainService依然能被合理地注入到MainController的成员变量里。 BeanPostProcessor(该接口下文没使用,大家可以自己试试) DisposableBean
在bean对象被销毁的时候,spring会调用该接口提供的方法。 注意,如果程序中还有其他线程在持续运行,则Springboot不会主动关闭,也不会调用destroy()方法。即便你在启动类中使用ConfigurableApplicationContext 对象的stop方法也无效。spring必须等待其他线程释放资源以后才能退出程序。 先看看本程序使用的依赖
<?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/>
</ 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;
@Override
public void setBeanName ( String name) {
System. out. println ( "setBeanName:" + name) ;
}
@Override
public void setBeanFactory ( BeanFactory beanFactory) throws BeansException {
}
@Override
public void setApplicationContext ( ApplicationContext applicationContext) throws BeansException {
AutowireCapableBeanFactory beanFactory = applicationContext. getAutowireCapableBeanFactory ( ) ;
}
@Override
public void afterPropertiesSet ( ) throws Exception {
}
@Override
public void postProcessBeanDefinitionRegistry ( BeanDefinitionRegistry registry) throws BeansException {
}
@Override
public void postProcessBeanFactory ( ConfigurableListableBeanFactory beanFactory) throws BeansException {
Object user = beanFactory. getBean ( "user" ) ;
}
public Object postProcessBeforeInitialization ( Object bean, String beanName) throws BeansException {
return null;
}
public Object postProcessAfterInitialization ( Object bean, String beanName) throws BeansException {
return null;
}
@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;
@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;
}
@Override
public void setBeanName ( String name) {
System. out. println ( "setBeanName:" + name) ;
}
@Override
public void setBeanFactory ( BeanFactory beanFactory) throws BeansException {
}
@Override
public void setApplicationContext ( ApplicationContext applicationContext) throws BeansException {
}
@Override
public void afterPropertiesSet ( ) throws Exception {
}
@Override
public void postProcessBeanDefinitionRegistry ( BeanDefinitionRegistry registry) throws BeansException {
}
@Override
public void postProcessBeanFactory ( ConfigurableListableBeanFactory beanFactory) throws BeansException {
Object user = beanFactory. getBean ( "user" ) ;
}
public Object postProcessBeforeInitialization ( Object bean, String beanName) throws BeansException {
return null;
}
public Object postProcessAfterInitialization ( Object bean, String beanName) throws BeansException {
return null;
}
@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;
@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;
}
@Override
public void setBeanName ( String name) {
System. out. println ( "setBeanName:" + name) ;
}
@Override
public void setBeanFactory ( BeanFactory beanFactory) throws BeansException {
}
@Override
public void setApplicationContext ( ApplicationContext applicationContext) throws BeansException {
}
@Override
public void afterPropertiesSet ( ) throws Exception {
}
@Override
public void postProcessBeanDefinitionRegistry ( BeanDefinitionRegistry registry) throws BeansException {
}
@Override
public void postProcessBeanFactory ( ConfigurableListableBeanFactory beanFactory) throws BeansException {
Object user = beanFactory. getBean ( "user" ) ;
}
public Object postProcessBeforeInitialization ( Object bean, String beanName) throws BeansException {
return null;
}
public Object postProcessAfterInitialization ( Object bean, String beanName) throws BeansException {
return null;
}
@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获取对象,然后把对象重新注入进去。 但是还是得重申一遍,实现了BeanDefinitionRegistryPostProcessor或者BeanFactoryPostProcessor接口后,会导致@Autowired,@Resource等注入方法无效,这点要切记! 销毁的顺序
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;
public interface ObserverForInit {
void observerInit ( ) ;
}
package com. wu. smartport. test;
import com. wu. smartport. controller. ObserverForInit;
import org. springframework. stereotype. Component;
@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;
@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 ( ) ;
}
}
}
private void analysisObject ( Object bean) {
analysisInterface ( bean) ;
analysisAnnotation ( bean) ;
}
private void analysisInterface ( Object bean) {
Class< ? > beanClass = bean. getClass ( ) ;
Class< ? > [ ] interfaces = beanClass. getInterfaces ( ) ;
for ( Class infs : interfaces) {
if ( infs. equals ( ObserverForInit. class ) ) {
( ( ObserverForInit) bean) . observerInit ( ) ;
}
}
}
private void analysisAnnotation ( Object bean) {
}
}
4.2 按序初始化
如果对初始化的顺序有自己要求,可以采取如下的方法。至于4.1中的遍历顺序,读者可以自行研究,但建议自己写顺序,否则一旦springboot框架内部有变,咱们程序内部的初始顺序可能会出问题。 设置一个TreeSet 并给定排序策略,遍历接口的时候,先将找到的对象放入TreeSet中排序,再遍历完成之后再执行相应的操作 修改后的接口
package com. wu. smartport. controller;
public interface ObserverForInit {
void observerInit ( ) ;
int getInitOrder ( ) ;
}
@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;
@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 ( ) ;
}
private void analysisObject ( Object bean) {
analysisInterface ( bean) ;
analysisAnnotation ( bean) ;
}
private void analysisByAfterIterator ( ) {
for ( ObserverForInit o : inits) {
o. observerInit ( ) ;
}
}
private void analysisInterface ( Object bean) {
Class< ? > beanClass = bean. getClass ( ) ;
Class< ? > [ ] interfaces = beanClass. getInterfaces ( ) ;
for ( Class infs : interfaces) {
if ( infs. equals ( ObserverForInit. class ) ) {
inits. add ( ( ObserverForInit) bean) ;
}
}
}
private void analysisAnnotation ( Object bean) {
}
}
5 基于 Springboot 实现冯诺依曼结构
下面讲解一个骚操作 冯诺依曼结构:将程序和数据分别存储在内存当中 基于这种思想,我们不光可以把数据存储在容器当中,我们还可以把代码也存储在springboot容器当中。 创建一个Bean对象,实现BeanFactoryPostProcessor接口,在运行到该方法的时候,大部分的对象已经被装入了spring容器中。你可以在之后必要的地方从spring容器中提取该代码执行。
package com. wu. smartport. test;
import com. wu. smartport. SmartportApplication;
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;
@Component
public class Manager implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory ( ConfigurableListableBeanFactory beanFactory) throws BeansException {
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) ;
DefaultListableBeanFactory factory = ( DefaultListableBeanFactory) beanFactory;
factory. registerSingleton ( INIT_METHODS, arr) ;
}
}
在之后一定会运行到的代码,比如启动类之后,可以执行指定的代码段。
package com. wu. smartport;
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;
@SpringBootApplication
public class SmartportApplication {
private static volatile ConfigurableApplicationContext run;
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 ( ) ;
}
}
}