Spring是我们经常使用的一个框架,它功能之一是提供了我们管理bean对象的手段,而且它提供了很多钩子方法给我们使用。什么是钩子方法呢?钩子方法就是:在bean的生命周期之中,经历了一系列的过程之中,Spring留给我们的一个后门,让我们能在Spring的生命周期之中执行我们想要的方法,从而实现我们想要的功能。接下来我们介绍一下生命周期,然后一个一个介绍我见过的样例或者我自己写的样例。
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的两个注意事项:
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。这个权限非常大。
其实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