Spring是我們經常使用的一個框架,它功能之一是提供了我們管理bean對象的手段,而且它提供了很多鉤子方法給我們使用。什麼是鉤子方法呢?鉤子方法就是:在bean的生命週期之中,經歷了一系列的過程之中,Spring留給我們的一個後門,讓我們能在Spring的生命週期之中執行我們想要的方法,從而實現我們想要的功能。接下來我們介紹一下生命週期,然後一個一個介紹我見過的樣例或者我自己寫的樣例。
Spring生命週期的各種Aware
Spring的生命週期(我們撇開網絡上很多資料,因爲我覺得網絡上很多資料要麼不全,要麼分不清context和beanFactory,然後將context的一些過程歸入beanFactory之中。我這裏只看Spring官方文檔,我看的是5.3.0-SNAPSHOT版本的。)
上面列表說的114個初始化方法,13個銷燬方法。這就是我說的鉤子方法,只要你進程並實現了對應的方法,spring就會幫我們調用這些方法。
然後針對上面的bean lifecycle 我這裏用一個簡單的例子給大家演示一下:
public class BeanLifecycle implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware,
EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware,
ApplicationContextAware, ServletContextAware, BeanPostProcessor, InitializingBean, DestructionAwareBeanPostProcessor,
DisposableBean{
/**
* BeanNameAware 的 setBeanName,這個是第一個觸發
*/
@Override
public void setBeanName(String s) {
System.out.println("第一個執行 bean name = ");
}
/**
* BeanClassLoaderAware 的 setBeanClassLoader
*/
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("第二個執行 classLoader = ");
}
/**
* BeanFactoryAware 的 setBeanFactory
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("第三個執行 beanFactory = ");
}
/**
* EnvironmentAware 的 setEnvironment
*/
@Override
public void setEnvironment(Environment environment) {
System.out.println("第四個執行 environment = ");
}
/**
* EmbeddedValueResolverAware 的 EmbeddedValueResolverAware
*/
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
System.out.println("第五個執行 resolver = ");
}
/**
* ResourceLoaderAware 的 setResourceLoader
*/
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
System.out.println("第六個執行 resourceLoader = " );
}
/**
* ApplicationEventPublisherAware 的 setApplicationEventPublisher
*/
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
System.out.println("第七個執行 applicationEventPublisher = ");
}
/**
* MessageSourceAware 的 setMessageSource
*/
@Override
public void setMessageSource(MessageSource messageSource) {
System.out.println("第八個執行 messageSource = " );
}
/**
* ApplicationContextAware 的 setApplicationContext
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("第九個執行 applicationContext = ");
}
/**
* ServletContextAware 的 setServletContext
*/
@Override
public void setServletContext(ServletContext servletContext) {
System.out.println("第十個執行 servletContext = " );
}
/**
* BeanPostProcessor 的 postProcessBeforeInitialization
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第十一個執行 postProcessBeforeInitialization bean = " );
System.out.println("第十一個執行 postProcessBeforeInitialization beanName = " );
return bean;
}
/**
* InitializingBean 的 afterPropertiesSet
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("第十二個執行 = afterPropertiesSet");
}
/**
* 指定 的 initMethod
*/
public void initMethod() {
System.out.println("第十三個執行 = initMethod");
}
/**
* BeanPostProcessor 的 postProcessAfterInitialization
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第十四個執行 postProcessAfterInitialization bean = " );
System.out.println("第十四個執行 postProcessAfterInitialization beanName = " );
return bean;
}
/**
* DestructionAwareBeanPostProcessor 的 postProcessBeforeDestruction
*/
@Override
public void postProcessBeforeDestruction(Object o, String s) throws BeansException {
System.out.println("第一個執行的銷燬方法 o = " );
System.out.println("第一個執行的銷燬方法 s = " );
}
/**
* DisposableBean 的 destroy
*/
@Override
public void destroy() throws Exception {
System.out.println("第二個執行的銷燬方法 = destroy");
}
public void destroyMethod() {
System.out.println("第三個執行的銷燬方法 ");
}
}
然後我創建了下面一個測試用例:
@SpringBootApplication
public class LifecycleMain {
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public BeanLifecycle beanLifecycle() {
return new BeanLifecycle();
}
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public BeanLifecycle beanLifecycle2() {
return new BeanLifecycle();
}
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplication().run(LifecycleMain.class);
context.close(); //這個方法用來觸發destroy-method
}
}
output如下:
第一個執行 bean name =
第二個執行 classLoader =
第三個執行 beanFactory =
第四個執行 environment =
第五個執行 resolver =
第六個執行 resourceLoader =
第七個執行 applicationEventPublisher =
第八個執行 messageSource =
第九個執行 applicationContext =
第十二個執行 = afterPropertiesSet
第十三個執行 = initMethod
第一個執行 bean name =
第二個執行 classLoader =
第三個執行 beanFactory =
第四個執行 environment =
第五個執行 resolver =
第六個執行 resourceLoader =
第七個執行 applicationEventPublisher =
第八個執行 messageSource =
第九個執行 applicationContext =
第十二個執行 = afterPropertiesSet
第十三個執行 = initMethod
第十一個執行 bean =
第十一個執行 beanName =
第十一個執行 bean =
第十一個執行 beanName =
第十四個執行 bean =
第十四個執行 beanName =
第十四個執行 bean =
第十四個執行 beanName =
第二個執行的銷燬方法 = destroy
第三個執行的銷燬方法
第二個執行的銷燬方法 = destroy
第三個執行的銷燬方法
這裏我把後面輸出的對象都去掉了,因爲輸出結果太長影響我們觀看。
然後我先簡單說說Aware,Aware英文翻譯是知道的意思,Aware接口作用就是其實就是 你想知道什麼信息,然後就實現什麼樣的Aware,Spring會通過setXXX方法,將你想要知道的信息通過參數傳遞給你。
所以 BeanNameAware, BeanClassLoaderAware, BeanFactoryAware……的作用就是給對應的Bean回設這個Bean想知道的信息。
而這裏的有個小疑問:爲什麼第十個執行的Bean沒執行呢?而想象之中第十一個執行的方法在第十三個方法之後執行呢?
第一個問題是我們沒有對應的Servlet。
第二個問題:其實BeanPostProcessor是一個對所有Bean都會攔截的方法,如果我們想要在這個bean之前執行,我們需要在context的refresh階段之前添加進去而不是通過bean註冊進去,我們通過另外一種方式試試。
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getBeanFactory().addBeanPostProcessor(new BeanLifecycle());
context.register(BeanLifecycle.class);
context.refresh();
context.getBean(BeanLifecycle.class);
}
output如下:
22:34:48.200 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
第十一個執行 postProcessBeforeInitialization bean =
第十一個執行 postProcessBeforeInitialization beanName =
第十四個執行 postProcessAfterInitialization bean =
第十四個執行 postProcessAfterInitialization beanName =
22:34:48.227 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
第十一個執行 postProcessBeforeInitialization bean =
第十一個執行 postProcessBeforeInitialization beanName =
第十四個執行 postProcessAfterInitialization bean =
第十四個執行 postProcessAfterInitialization beanName =
22:34:48.229 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
第十一個執行 postProcessBeforeInitialization bean =
第十一個執行 postProcessBeforeInitialization beanName =
第十四個執行 postProcessAfterInitialization bean =
第十四個執行 postProcessAfterInitialization beanName =
22:34:48.230 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
第十一個執行 postProcessBeforeInitialization bean =
第十一個執行 postProcessBeforeInitialization beanName =
第十四個執行 postProcessAfterInitialization bean =
第十四個執行 postProcessAfterInitialization beanName =
22:34:48.232 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
第十一個執行 postProcessBeforeInitialization bean =
第十一個執行 postProcessBeforeInitialization beanName =
第十四個執行 postProcessAfterInitialization bean =
第十四個執行 postProcessAfterInitialization beanName =
22:34:48.235 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'beanLifecycle'
第一個執行 bean name =
第二個執行 classLoader =
第三個執行 beanFactory =
第十一個執行 postProcessBeforeInitialization bean =
第十一個執行 postProcessBeforeInitialization beanName =
第四個執行 environment =
第五個執行 resolver =
第六個執行 resourceLoader =
第七個執行 applicationEventPublisher =
第八個執行 messageSource =
第九個執行 applicationContext =
第十二個執行 = afterPropertiesSet
第十四個執行 postProcessAfterInitialization bean =
第十四個執行 postProcessAfterInitialization beanName =
爲什麼上面的postProcessAfterInitialization方法執行了好多次呢?
我們看看 BeanPostProcessor 的postProcessBeforeInitialization
方法的註解:
Apply this BeanPostProcessor to the given new bean instance before any bean initialization callbacks (like InitializingBean’s afterPropertiesSet
or a custom init-method). The bean will already be populated with property values. The returned bean instance may be a wrapper around the original.
大意就是:這個方法會被每個bean 初始化之前都會回調這個方法,比如 會在InitializingBean’s afterPropertiesSet或bean自定義的一個init-method方法調用之前回調這個方法。
然後看看postProcessAfterInitialization
的註解:
Apply this BeanPostProcessor to the given new bean instance after any bean initialization callbacks (like InitializingBean’s afterPropertiesSet or a custom init-method). The bean will already be populated with property values. The returned bean instance may be a wrapper around the original.
大意就是:這個方法會在每個bean初始化之後都會回調這個方法。
這樣就解釋了爲什麼的 postProcessBeforeInitialization
和 postProcessAfterInitialization
方法會被打印這麼多次,因爲它是每個bean被初始化一次,它都會被調用一次。那麼我設想是不是在需要對某些 bean,或者是底層接口的一個bean,我想攔截下來並且做一點修飾,這樣就不需要入侵到底層代碼裏面去了。
然後看了下 BeanPostProcessor 的註解:
Factory hook that allows for custom modification of new bean instances — for example, checking for marker interfaces or wrapping beans with proxies.
大意就是:Factory的hook(鉤子方法),可以定製修改一個新的bean實例,比如檢查interfaces的創建條件對不對,使用代理包裝某個beans。
不過上面有個結果比較奇怪:爲什麼的postProcessBeforeInitialization
會在 EnvironmentAware之前執行。這個挖個坑,後面地細細研究一下。
這裏給大家一個我使用BeanPostProcessor的例子。
@Configuration
public class MysqlConfigAdapter implements BeanPostProcessor{
@Value("mysql.username")
private String username;
@Value("mysql.password")
private String password;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof XxxDatabase) {
((XxxDatabase)bean).setUsername(username);
((XxxDatabase)bean).setPassword(password);
}
return bean;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
上面的例子是本人在實際生產運用中使用到的例子(改造過),當時是因爲使用了第三方中間件,而爲了能讓第三方中間件接入配置中心(比如阿波羅,nacos),而不侵入對方的代碼,就在外層寫了個適配器(適配器模式)。攔截下對應的bean,並且修改裏面的值,再給出去。恰好符合註解講的那樣:The returned bean instance may be a wrapper around the original.
除了上面的例子之外,我們再說一點BeanPostProcessor的兩個注意事項:
- 註冊方式:BeanPostProcessor可以直接被ApplicationContext發現,也可以手動通過BeanFactory註冊。
- 順序:有多個BeanPostProcessor的時候,通過ApplicationContext發現的就會看這個bean是否implement了PriorityOrdered和Ordered接口,按照這兩個的順序來排序(PriorityOrdered優先於Ordered)。如果是通過手動註冊來的,就會忽略掉這些屬性,只看添加的順序來決定先後順序。最後@Order是無效的,目前還沒有實現(5.3.0-SNAPSHOT)版本。
BeanFactoryPostProcessor
PostProcessor 其實除了這個BeanPostProcessor 之外,之前看源碼的時候也注意到了有另外一個:BeanFactoryPostProcessor。然後我們看看BeanFactoryPostProcessor
源碼註解解釋。
Factory hook that allows for custom modification of an application context’s bean definitions, adapting the bean property values of the context’s underlying bean factory.
大意就是說:這是要給針對BeanFactory的鉤子方法,是一個可以對applicationContext的BeanFactory修改的方法。修改這個context的beanfactory的properties value。這個權限非常大。
- 它的註冊方式也分兩種:通過applicationContext自動探測,通過ConfigurableApplicationContext.addBeanFactoryPostProcessor手動註冊。
- 它的順序性和BeanPostProcessor一樣
其實BeanFactoryPostProcessor
是要給非常強大的接口,我們的@Configuration功能,SpringBoot的自動裝配還有Spring-Mybatis的適配都是靠這個來實現的。具體的實現可以參考ConfigurationClassPostProcessor
,如果後面有機會,可以再給大家看看ConfigurationClassPostProcessor它的實現。(再挖個坑。)
BeanFactoryPostProcessor 和BeanPostProcessor有個很大的區別是:BeanFactoryPostProcessor 的執行時機很早,在所有的bean初始化包括那些aware賦值之前就執行了,而BeanPostProcessor是每個bean初始化之前執行postProcessBeforeInitialization,初始化之後執行postProcessAfterInitialization。
好了,這期就到這裏了。
那麼我們把各種各樣的Aware看做一個階段,我們是否可以得出這樣的結論:
BeanFactoryPostProcessor.postProcessBeanFactory -->
Aware -->
BeanPostProcessor.postProcessBeforeInitialization -->
initialBean -->
initMethod -->
BeanPostProcessor.postProcessAfterInitialization -->
DisposableBean -->
destroyMethod
更多精彩內容歡迎關注我的微信公衆號: