spring 强大的钩子函数总结
Spring是我们经常使用的一个框架,它功能之一是提供了我们管理bean对象的手段,而且它提供了很多钩子方法给我们使用。什么是钩子方法呢?钩子方法就是:在bean的生命周期之中,经历了一系列的过程之中,Spring留给我们的一个后门,让我们能在Spring的生命周期之中执行我们想要的方法,从而实现我们想要的功能。接下来我们介绍一下生命周期,然后一个一个介绍我见过的样例或者我自己写的样例。
Spring生命周期的各种Aware
Spring的生命周期(我们撇开网络上很多资料,因为我觉得网络上很多资料要么不全,要么分不清context和beanFactory,然后将context的一些过程归入beanFactory之中。我这里只看Spring官方文档,我看的是5.3.0-SNAPSHOT版本的。)
上面列表说的114个初始化方法,13个销毁方法。这就是我说的钩子方法,只要你进程并实现了对应的方法,spring就会帮我们调用这些方法。
然后针对上面的bean lifecycle 我这里用一个简单的例子给大家演示一下:
<span style="color:#000000"><code class="language-java"><span style="color:#6679cc">public</span> <span style="color:#6679cc">class</span> BeanLifecycle <span style="color:#6679cc">implements</span> BeanNameAware<span style="color:#999999">,</span> BeanClassLoaderAware<span style="color:#999999">,</span> BeanFactoryAware<span style="color:#999999">,</span> EnvironmentAware<span style="color:#999999">,</span>EmbeddedValueResolverAware<span style="color:#999999">,</span> ResourceLoaderAware<span style="color:#999999">,</span> ApplicationEventPublisherAware<span style="color:#999999">,</span> MessageSourceAware<span style="color:#999999">,</span>ApplicationContextAware<span style="color:#999999">,</span> ServletContextAware<span style="color:#999999">,</span> BeanPostProcessor<span style="color:#999999">,</span> InitializingBean<span style="color:#999999">,</span> DestructionAwareBeanPostProcessor<span style="color:#999999">,</span>DisposableBean<span style="color:#999999">{</span><span style="color:#6b7394">/*** BeanNameAware 的 setBeanName,这个是第一个触发*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setBeanName</span><span style="color:#999999">(</span>String s<span style="color:#999999">)</span> <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第一个执行 bean name = "</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** BeanClassLoaderAware 的 setBeanClassLoader*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setBeanClassLoader</span><span style="color:#999999">(</span>ClassLoader classLoader<span style="color:#999999">)</span> <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第二个执行 classLoader = "</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** BeanFactoryAware 的 setBeanFactory*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setBeanFactory</span><span style="color:#999999">(</span>BeanFactory beanFactory<span style="color:#999999">)</span> <span style="color:#6679cc">throws</span> BeansException <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第三个执行 beanFactory = "</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** EnvironmentAware 的 setEnvironment*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setEnvironment</span><span style="color:#999999">(</span>Environment environment<span style="color:#999999">)</span> <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第四个执行 environment = "</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** EmbeddedValueResolverAware 的 EmbeddedValueResolverAware*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setEmbeddedValueResolver</span><span style="color:#999999">(</span>StringValueResolver resolver<span style="color:#999999">)</span> <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第五个执行 resolver = "</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** ResourceLoaderAware 的 setResourceLoader*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setResourceLoader</span><span style="color:#999999">(</span>ResourceLoader resourceLoader<span style="color:#999999">)</span> <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第六个执行 resourceLoader = "</span> <span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** ApplicationEventPublisherAware 的 setApplicationEventPublisher*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setApplicationEventPublisher</span><span style="color:#999999">(</span>ApplicationEventPublisher applicationEventPublisher<span style="color:#999999">)</span> <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第七个执行 applicationEventPublisher = "</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** MessageSourceAware 的 setMessageSource*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setMessageSource</span><span style="color:#999999">(</span>MessageSource messageSource<span style="color:#999999">)</span> <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第八个执行 messageSource = "</span> <span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** ApplicationContextAware 的 setApplicationContext*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setApplicationContext</span><span style="color:#999999">(</span>ApplicationContext applicationContext<span style="color:#999999">)</span> <span style="color:#6679cc">throws</span> BeansException <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第九个执行 applicationContext = "</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** ServletContextAware 的 setServletContext*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setServletContext</span><span style="color:#999999">(</span>ServletContext servletContext<span style="color:#999999">)</span> <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第十个执行 servletContext = "</span> <span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** BeanPostProcessor 的 postProcessBeforeInitialization*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> Object <span style="color:#3d8fd1">postProcessBeforeInitialization</span><span style="color:#999999">(</span>Object bean<span style="color:#999999">,</span> String beanName<span style="color:#999999">)</span> <span style="color:#6679cc">throws</span> BeansException <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第十一个执行 postProcessBeforeInitialization bean = "</span> <span style="color:#999999">)</span><span style="color:#999999">;</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第十一个执行 postProcessBeforeInitialization beanName = "</span> <span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#6679cc">return</span> bean<span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** InitializingBean 的 afterPropertiesSet*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">afterPropertiesSet</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6679cc">throws</span> Exception <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第十二个执行 = afterPropertiesSet"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** 指定 的 initMethod*/</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">initMethod</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第十三个执行 = initMethod"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** BeanPostProcessor 的 postProcessAfterInitialization*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> Object <span style="color:#3d8fd1">postProcessAfterInitialization</span><span style="color:#999999">(</span>Object bean<span style="color:#999999">,</span> String beanName<span style="color:#999999">)</span> <span style="color:#6679cc">throws</span> BeansException <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第十四个执行 postProcessAfterInitialization bean = "</span> <span style="color:#999999">)</span><span style="color:#999999">;</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第十四个执行 postProcessAfterInitialization beanName = "</span> <span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#6679cc">return</span> bean<span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** DestructionAwareBeanPostProcessor 的 postProcessBeforeDestruction*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">postProcessBeforeDestruction</span><span style="color:#999999">(</span>Object o<span style="color:#999999">,</span> String s<span style="color:#999999">)</span> <span style="color:#6679cc">throws</span> BeansException <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第一个执行的销毁方法 o = "</span> <span style="color:#999999">)</span><span style="color:#999999">;</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第一个执行的销毁方法 s = "</span> <span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6b7394">/*** DisposableBean 的 destroy*/</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">destroy</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6679cc">throws</span> Exception <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第二个执行的销毁方法 = destroy"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">destroyMethod</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#3d8fd1">println</span><span style="color:#999999">(</span><span style="color:#ac9739">"第三个执行的销毁方法 "</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span>
<span style="color:#999999">}</span>
</code></span>
然后我创建了下面一个测试用例:
<span style="color:#000000"><code class="language-java"><span style="color:#999999">@SpringBootApplication</span>
<span style="color:#6679cc">public</span> <span style="color:#6679cc">class</span> LifecycleMain <span style="color:#999999">{</span><span style="color:#999999">@Bean</span><span style="color:#999999">(</span>initMethod <span style="color:#ac9739">=</span> <span style="color:#ac9739">"initMethod"</span><span style="color:#999999">,</span> destroyMethod <span style="color:#ac9739">=</span> <span style="color:#ac9739">"destroyMethod"</span><span style="color:#999999">)</span><span style="color:#6679cc">public</span> BeanLifecycle <span style="color:#3d8fd1">beanLifecycle</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span><span style="color:#6679cc">return</span> <span style="color:#6679cc">new</span> BeanLifecycle<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#999999">@Bean</span><span style="color:#999999">(</span>initMethod <span style="color:#ac9739">=</span> <span style="color:#ac9739">"initMethod"</span><span style="color:#999999">,</span> destroyMethod <span style="color:#ac9739">=</span> <span style="color:#ac9739">"destroyMethod"</span><span style="color:#999999">)</span><span style="color:#6679cc">public</span> BeanLifecycle <span style="color:#3d8fd1">beanLifecycle2</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span><span style="color:#6679cc">return</span> <span style="color:#6679cc">new</span> BeanLifecycle<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">static</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">main</span><span style="color:#999999">(</span>String<span style="color:#999999">[</span><span style="color:#999999">]</span> args<span style="color:#999999">)</span> <span style="color:#999999">{</span>ConfigurableApplicationContext context <span style="color:#ac9739">=</span> <span style="color:#6679cc">new</span> SpringApplication<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#3d8fd1">run</span><span style="color:#999999">(</span>LifecycleMain<span style="color:#999999">.</span><span style="color:#6679cc">class</span><span style="color:#999999">)</span><span style="color:#999999">;</span>context<span style="color:#999999">.</span><span style="color:#3d8fd1">close</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6b7394">//这个方法用来触发destroy-method</span><span style="color:#999999">}</span>
<span style="color:#999999">}</span>
</code></span>
output如下:
<span style="color:#000000"><code>第一个执行 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
第三个执行的销毁方法
</code></span>
这里我把后面输出的对象都去掉了,因为输出结果太长影响我们观看。
然后我先简单说说Aware,Aware英文翻译是知道的意思,Aware接口作用就是其实就是 你想知道什么信息,然后就实现什么样的Aware,Spring会通过setXXX方法,将你想要知道的信息通过参数传递给你。
所以 BeanNameAware, BeanClassLoaderAware, BeanFactoryAware……的作用就是给对应的Bean回设这个Bean想知道的信息。
而这里的有个小疑问:为什么第十个执行的Bean没执行呢?而想象之中第十一个执行的方法在第十三个方法之后执行呢?
第一个问题是我们没有对应的Servlet。
第二个问题:其实BeanPostProcessor是一个对所有Bean都会拦截的方法,如果我们想要在这个bean之前执行,我们需要在context的refresh阶段之前添加进去而不是通过bean注册进去,我们通过另外一种方式试试。
<span style="color:#000000"><code class="language-java"><span style="color:#6679cc">public</span> <span style="color:#6679cc">static</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">main</span><span style="color:#999999">(</span>String<span style="color:#999999">[</span><span style="color:#999999">]</span> args<span style="color:#999999">)</span> <span style="color:#999999">{</span>AnnotationConfigApplicationContext context <span style="color:#ac9739">=</span> <span style="color:#6679cc">new</span> AnnotationConfigApplicationContext<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>context<span style="color:#999999">.</span><span style="color:#3d8fd1">getBeanFactory</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#3d8fd1">addBeanPostProcessor</span><span style="color:#999999">(</span><span style="color:#6679cc">new</span> BeanLifecycle<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span>context<span style="color:#999999">.</span><span style="color:#3d8fd1">register</span><span style="color:#999999">(</span>BeanLifecycle<span style="color:#999999">.</span><span style="color:#6679cc">class</span><span style="color:#999999">)</span><span style="color:#999999">;</span>context<span style="color:#999999">.</span><span style="color:#3d8fd1">refresh</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>context<span style="color:#999999">.</span><span style="color:#3d8fd1">getBean</span><span style="color:#999999">(</span>BeanLifecycle<span style="color:#999999">.</span><span style="color:#6679cc">class</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
</code></span>
output如下:
<span style="color:#000000"><code>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 =
</code></span>
为什么上面的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的例子。
<span style="color:#000000"><code class="language-java"><span style="color:#999999">@Configuration</span>
<span style="color:#6679cc">public</span> <span style="color:#6679cc">class</span> MysqlConfigAdapter <span style="color:#6679cc">implements</span> BeanPostProcessor<span style="color:#999999">{</span><span style="color:#999999">@Value</span><span style="color:#999999">(</span><span style="color:#ac9739">"mysql.username"</span><span style="color:#999999">)</span><span style="color:#6679cc">private</span> String username<span style="color:#999999">;</span><span style="color:#999999">@Value</span><span style="color:#999999">(</span><span style="color:#ac9739">"mysql.password"</span><span style="color:#999999">)</span><span style="color:#6679cc">private</span> String password<span style="color:#999999">;</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> Object <span style="color:#3d8fd1">postProcessAfterInitialization</span><span style="color:#999999">(</span>Object bean<span style="color:#999999">,</span> String beanName<span style="color:#999999">)</span> <span style="color:#6679cc">throws</span> BeansException <span style="color:#999999">{</span><span style="color:#6679cc">if</span> <span style="color:#999999">(</span>bean <span style="color:#6679cc">instanceof</span> XxxDatabase<span style="color:#999999">)</span> <span style="color:#999999">{</span><span style="color:#999999">(</span><span style="color:#999999">(</span>XxxDatabase<span style="color:#999999">)</span>bean<span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#3d8fd1">setUsername</span><span style="color:#999999">(</span>username<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">(</span><span style="color:#999999">(</span>XxxDatabase<span style="color:#999999">)</span>bean<span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#3d8fd1">setPassword</span><span style="color:#999999">(</span>password<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6679cc">return</span> bean<span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#999999">@Override</span><span style="color:#6679cc">public</span> <span style="color:#6679cc">void</span> <span style="color:#3d8fd1">setApplicationContext</span><span style="color:#999999">(</span>ApplicationContext applicationContext<span style="color:#999999">)</span> <span style="color:#6679cc">throws</span> BeansException <span style="color:#999999">{</span><span style="color:#6679cc">this</span><span style="color:#999999">.</span>applicationContext <span style="color:#ac9739">=</span> applicationContext<span style="color:#999999">;</span><span style="color:#999999">}</span>
<span style="color:#999999">}</span>
</code></span>
上面的例子是本人在实际生产运用中使用到的例子(改造过),当时是因为使用了第三方中间件,而为了能让第三方中间件接入配置中心(比如阿波罗,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看做一个阶段,我们是否可以得出这样的结论:
<span style="color:#000000"><code>BeanFactoryPostProcessor.postProcessBeanFactory -->
Aware -->
BeanPostProcessor.postProcessBeforeInitialization -->
initialBean -->
initMethod -->
BeanPostProcessor.postProcessAfterInitialization -->
DisposableBean -->
destroyMethod</code></span>
spring 强大的钩子函数总结相关推荐
- java钩子函数(hook)以spring源码为例
一.什么是钩子函数 请问在Spring中,如果JVM异常终止,Spring是如何保证会释放掉占用的资源,比如说数据库连接等资源呢?钩子函数非常简单,简单到只用摘抄一段Spring代码即可. 二.问题 ...
- 用Delphi实现Windows的鼠标钩子函数
用Delphi实现Windows的鼠标钩子函数 Delphi是基于PASCAL语言的Windows编程工具,功能十分强大.然而在Delphi的帮助 文件中,对Windows API函数的说明沿袭了 V ...
- Vue钩子函数mounted实现进入页面立即查询的功能案例
Vue的钩子函数:当执行到某一阶段就会执行的方法/函数.就相当于spring中bean的生命周期一样.
- C语言 - 钩子函数详解
自学到线程池 被各种函数指针的套娃操作套蒙了, 所以写一篇来总结一下. 首先要搞清楚几个事情 函数指针和指针函数 函数指针是指针,可以指向任一"同类型"的函数 指针函数是函数,这个 ...
- k8s pod生命周期、初始化容器、钩子函数、容器探测、重启策略
pod结构 Pause容器 Pause容器是每个Pod都会有的一个根容器,它的作用有两个 可以以它为根据,评估整个pod的健康状态 可以在根容器上设置IP地址,其他容器都以此IP(Pod IP),以实 ...
- VUE 钩子函数超详细解析
点击上方蓝色字体关注我吧 一起学习,一起进步,做积极的人! 前言 Vue 实例在被创建时,会经过一系列的初始化过程,初始化过程中会运行一些函数,叫做生命周期钩子函数,通过运用钩子函数,用户在可以在Vu ...
- WIN32汇编: 24.WINDOWS钩子函数
第二十四课 WINDOWS钩子函数 本课中我们将要学习WINDOWS钩子函数的使用方法.WINDOWS钩子函数的功能非常强大,有了它您可以探测其它进程并且改变其它进程的行为. 理论: WINDOWS的 ...
- Vue2.0 探索之路——生命周期和钩子函数的一些理解
前言 在使用vue一个多礼拜后,感觉现在还停留在初级阶段,虽然知道怎么和后端做数据交互,但是对于mounted这个挂载还不是很清楚的.放大之,对vue的生命周期不甚了解.只知道简单的使用,而不知道为什 ...
- 使用钩子函数[4] - 钩子链和 CallNextHookEx 的返回值
SetWindowsHookEx 函数的第一个参数表示钩子类型, 共有 14 种选择, 前面我们已经用过两种: WH_KEYBOARD.WH_MOUSE. 系统会为每一种类型的钩子建立一个表(那就是 ...
最新文章
- RapidFramework使用Oracle的步骤
- Android API Guides 安卓API指导----第一部分:Introduction(介绍)
- PHP设置块注释的模板
- java去除json 转移,Spring MVC返回的json去除根节点名称的方法
- [CQOI2012]交换棋子【网络流】【费用流】
- 物联网在改造海上钻井平台监测方面发挥着关键作用
- 登录超时服务器未响应,怎样解决超时时间已到、在操作完成之前超时时间已过或服务器未响应的问题?...
- 公众号回复单个图文消息
- QA:Visual C# 2008 compiler could not be created.
- 关于x64dbg里面的Assemble
- 最新破解无线网络破解教程,一键破解wpa/wpa2密码软件下载。破解不用抓包不用跑字典。快速破解wpa/wpa2密码...
- 【python实战】23个爬虫项目源码:微信、淘宝、知乎、微博...
- Python数据库编程
- 软件开发流程:软件运维流程
- Linux中各种 command not found问题解决
- 【无标题】HTMLCSS学习总结
- 国家知识产权局宣告易百珑自发电专利权有效
- 计算机辅助设计技术领域的应用,关于计算机辅助设计技术在规划设计中的应用...
- 这有300+门刚刚开课的编程计算机科学免费课程大集合
- 蓝牙规范-Vol 6:低功耗控制器 Part A 物理层规范
热门文章
- 工业设计公司的办公环境有哪些特点?
- prctl()函数应用
- python 同花顺thstrader_GitHub - hooddonkey/THSTrader: 量化交易。最新版通用版同花顺客户端的python API。(Python3)...
- Dell服务器RAID卡介绍及监控
- 微软GitHub旗帜鲜明抵制996!
- oak深度相机入门教程-创建自定义模型
- 铅卤化物钙钛矿ABX3晶体薄膜量子点
- Redis数据结构之hash
- day19总结和作业
- 佐客牛排机器人餐厅_这些机器人服务员上菜的网红餐厅你一定喜欢丨打卡指南...