当前位置:   article > 正文

spring environment_深究Spring中Bean的生命周期

setenvironment 什么时候调用

前言

这其实是一道面试题,是我在面试百度的时候被问到的,当时没有答出来(因为自己真的很菜),后来在网上寻找答案,看到也是一头雾水,直到看到了《Spring in action》这本书,书上有对Bean声明周期的大致解释,但是没有代码分析,所以就自己上网寻找资料,一定要把这个Bean生命周期弄明白!

网上大部分都是验证的Bean 在面试问的生命周期,其实查阅JDK还有一个完整的Bean生命周期,这同时也验证了书是具有片面性的,最fresh 的资料还是查阅原始JDK!!!

一、Bean 的完整生命周期

在传统的Java应用中,bean的生命周期很简单,使用Java关键字 new 进行Bean 的实例化,然后该Bean 就能够使用了。一旦bean不再被使用,则由Java自动进行垃圾回收。

相比之下,Spring管理Bean的生命周期就复杂多了,正确理解Bean 的生命周期非常重要,因为Spring对Bean的管理可扩展性非常强,下面展示了一个Bean的构造过程

2cae44c1149f00ad2ab1bccd471738ba.png

Bean 的生命周期

如上图所示,Bean 的生命周期还是比较复杂的,下面来对上图每一个步骤做文字描述:

  1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
  2. Bean实例化后对将Bean的引入和值注入到Bean的属性中
  3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
  4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
  5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
  6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
  7. 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
  8. 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
  9. 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
  10. 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
上面是Spring 中Bean的核心接口和生命周期,面试回答上述过程已经足够了。但是翻阅JavaDoc文档发现除了以上接口外,还有另外的初始化过程涉及的接口:摘自org.springframework.beans.factory.BeanFactory, 全部相关接口如下,上述已有的就不用着重标注,把额外的相关接口着重标注下

3030364703fd755d9aa7a1b06cd98602.png

Bean 完整的生命周期

文字解释如下:

————————————初始化————————————

  • BeanNameAware.setBeanName() 在创建此bean的bean工厂中设置bean的名称,在普通属性设置之后调用,在InitializinngBean.afterPropertiesSet()方法之前调用
  • BeanClassLoaderAware.setBeanClassLoader(): 在普通属性设置之后,InitializingBean.afterPropertiesSet()之前调用
  • BeanFactoryAware.setBeanFactory() : 回调提供了自己的bean实例工厂,在普通属性设置之后,在InitializingBean.afterPropertiesSet()或者自定义初始化方法之前调用
  • EnvironmentAware.setEnvironment(): 设置environment在组件使用时调用
  • EmbeddedValueResolverAware.setEmbeddedValueResolver(): 设置StringValueResolver 用来解决嵌入式的值域问题
  • ResourceLoaderAware.setResourceLoader(): 在普通bean对象之后调用,在afterPropertiesSet 或者自定义的init-method 之前调用,在 ApplicationContextAware 之前调用。
  • ApplicationEventPublisherAware.setApplicationEventPublisher(): 在普通bean属性之后调用,在初始化调用afterPropertiesSet 或者自定义初始化方法之前调用。在 ApplicationContextAware 之前调用。
  • MessageSourceAware.setMessageSource(): 在普通bean属性之后调用,在初始化调用afterPropertiesSet 或者自定义初始化方法之前调用,在 ApplicationContextAware 之前调用。
  • ApplicationContextAware.setApplicationContext(): 在普通Bean对象生成之后调用,在InitializingBean.afterPropertiesSet之前调用或者用户自定义初始化方法之前。在ResourceLoaderAware.setResourceLoader,ApplicationEventPublisherAware.setApplicationEventPublisher,MessageSourceAware之后调用。
  • ServletContextAware.setServletContext(): 运行时设置ServletContext,在普通bean初始化后调用,在InitializingBean.afterPropertiesSet之前调用,在 ApplicationContextAware 之后调用注:是在WebApplicationContext 运行时
  • BeanPostProcessor.postProcessBeforeInitialization() : 将此BeanPostProcessor 应用于给定的新bean实例 在任何bean初始化回调方法(像是InitializingBean.afterPropertiesSet或者自定义的初始化方法)之前调用。这个bean将要准备填充属性的值。返回的bean示例可能被普通对象包装,默认实现返回是一个bean。
  • BeanPostProcessor.postProcessAfterInitialization() : 将此BeanPostProcessor 应用于给定的新bean实例 在任何bean初始化回调方法(像是InitializingBean.afterPropertiesSet或者自定义的初始化方法)之后调用。这个bean将要准备填充属性的值。返回的bean示例可能被普通对象包装
  • InitializingBean.afterPropertiesSet(): 被BeanFactory在设置所有bean属性之后调用(并且满足BeanFactory 和 ApplicationContextAware)。

————————————销毁————————————

在BeanFactory 关闭的时候,Bean的生命周期会调用如下方法:

  • DestructionAwareBeanPostProcessor.postProcessBeforeDestruction(): 在销毁之前将此BeanPostProcessor 应用于给定的bean实例。能够调用自定义回调,像是DisposableBean 的销毁和自定义销毁方法,这个回调仅仅适用于工厂中的单例bean(包括内部bean)
  • 实现了自定义的destory()方法

二、Bean 的生命周期验证

为了验证Bean生命周期的过程,有两种形式:一种是为面试而准备的,一种是为了解全过程而准备的,下面来看代码:

Book.class

  1. public class Book implements BeanNameAware,BeanFactoryAware,
  2. ApplicationContextAware,InitializingBean,DisposableBean {
  3. private String bookName;
  4. public Book(){
  5. System.out.println("Book Initializing ");
  6. }
  7. public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  8. System.out.println("Book.setBeanFactory invoke");
  9. }
  10. public void setBeanName(String name) {
  11. System.out.println("Book.setBeanName invoke");
  12. }
  13. public void destroy() throws Exception {
  14. System.out.println("Book.destory invoke");
  15. }
  16. public void afterPropertiesSet() throws Exception {
  17. System.out.println("Book.afterPropertiesSet invoke");
  18. }
  19. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  20. System.out.println("Book.setApplicationContext invoke");
  21. }
  22. public String getBookName() {
  23. return bookName;
  24. }
  25. public void setBookName(String bookName) {
  26. this.bookName = bookName;
  27. System.out.println("setBookName: Book name has set.");
  28. }
  29. public void myPostConstruct(){
  30. System.out.println("Book.myPostConstruct invoke");
  31. }
  32. // 自定义初始化方法
  33. @PostConstruct
  34. public void springPostConstruct(){
  35. System.out.println("@PostConstruct");
  36. }
  37. public void myPreDestory(){
  38. System.out.println("Book.myPreDestory invoke");
  39. System.out.println("---------------destroy-----------------");
  40. }
  41. // 自定义销毁方法
  42. @PreDestroy
  43. public void springPreDestory(){
  44. System.out.println("@PreDestory");
  45. }
  46. @Override
  47. protected void finalize() throws Throwable {
  48. System.out.println("------inside finalize-----");
  49. }
  50. }

自定义实现BeanPostProcessor 的MyBeanPostProcessor:

  1. public class MyBeanPostProcessor implements BeanPostProcessor {
  2. // 容器加载的时候会加载一些其他的bean,会调用初始化前和初始化后方法
  3. // 这次只关注book(bean)的生命周期
  4. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  5. if(bean instanceof Book){
  6. System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization");
  7. }
  8. return bean;
  9. }
  10. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  11. if(bean instanceof Book){
  12. System.out.println("MyBeanPostProcessor.postProcessAfterInitialization");
  13. }
  14. return bean;
  15. }
  16. }

在resources 目录下新建Bean-Lifecycle.xml

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  6. <!-- 扫描bean -->
  7. <context:component-scan base-package="com.bean.lifecycle"/>
  8. <!-- 实现了用户自定义初始化和销毁方法 -->
  9. <bean id="book" class="com.bean.lifecycle.Book" init-method="myPostConstruct" destroy-method="myPreDestory">
  10. <!-- 注入bean 属性名称 -->
  11. <property name="bookName" value="thingking in java" />
  12. </bean>
  13. <!--引入自定义的BeanPostProcessor-->
  14. <bean class="com.bean.lifecycle.MyBeanPostProcessor"/>
  15. </beans>

做一个启动类的测试,新建SpringBeanLifecycleApplication

  1. public class SpringBeanLifecycleApplication {
  2. public static void main(String[] args) throws InterruptedException {
  3. // 为面试而准备的Bean生命周期加载过程
  4. ApplicationContext context = new ClassPathXmlApplicationContext("Bean-Lifecycle.xml");
  5. Book book = (Book)context.getBean("book");
  6. System.out.println("Book name = " + book.getBookName());
  7. ((ClassPathXmlApplicationContext) context).destroy();
  8. }
  9. }

启动测试,输出结果如下:

  1. Book Initializing
  2. setBookName: Book name has set.
  3. Book.setBeanName invoke
  4. Book.setBeanFactory invoke
  5. Book.setApplicationContext invoke
  6. MyBeanPostProcessor.postProcessBeforeInitialization
  7. @PostConstruct
  8. Book.afterPropertiesSet invoke
  9. Book.myPostConstruct invoke
  10. MyBeanPostProcessor.postProcessAfterInitialization
  11. Book name = thingking in java
  12. @PreDestory
  13. Book.destory invoke
  14. Book.myPreDestory invoke
  15. ---------------destroy-----------------

为了验证Bean完整的生命周期,需要新建一个SubBookClass 继承Book类

  1. public class SubBookClass extends Book implements BeanClassLoaderAware,
  2. EnvironmentAware,EmbeddedValueResolverAware,ResourceLoaderAware,
  3. ApplicationEventPublisherAware,MessageSourceAware{
  4. private String bookSystem;
  5. public String getBookSystem() {
  6. return bookSystem;
  7. }
  8. public void setBookSystem(String bookSystem) {
  9. System.out.println("设置BookSystem 的属性值");
  10. this.bookSystem = bookSystem;
  11. }
  12. public void setBeanClassLoader(ClassLoader classLoader) {
  13. System.out.println("SubBookClass.setBeanClassLoader() 方法被调用了");
  14. }
  15. public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
  16. System.out.println("SubBookClass.setApplicationEventPublisher() 方法被调用了");
  17. }
  18. public void setEmbeddedValueResolver(StringValueResolver resolver) {
  19. System.out.println("SubBookClass.setEmbeddedValueResolver() 方法被调用了");
  20. }
  21. public void setEnvironment(Environment environment) {
  22. System.out.println("SubBookClass.setEnvironment() 方法被调用了");
  23. }
  24. public void setMessageSource(MessageSource messageSource) {
  25. System.out.println("SubBookClass.setMessageSource() 方法被调用了");
  26. }
  27. public void setResourceLoader(ResourceLoader resourceLoader) {
  28. System.out.println("SubBookClass.setResourceLoader() 方法被调用了");
  29. }
  30. }
上述SubBookClass类与Book是互补关系。

新建一个SubBean-Lifecycle.xml,注入SubBookClass

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  6. <bean id="bookClass" class="com.bean.lifecycle.SubBookClass" init-method="myPostConstruct" destroy-method="myPreDestory">
  7. <property name="bookSystem" value="Java System" />
  8. </bean>
  9. <bean class="com.bean.lifecycle.MyBeanPostProcessor"/>
  10. </beans>

完整的SpringBeanLifecycleApplication 如下:

  1. public class SpringBeanLifecycleApplication {
  2. public static void main(String[] args) throws InterruptedException {
  3. // 为面试而准备的Bean生命周期加载过程
  4. ApplicationContext context = new ClassPathXmlApplicationContext("Bean-Lifecycle.xml");
  5. Book book = (Book)context.getBean("book");
  6. System.out.println("Book name = " + book.getBookName());
  7. ((ClassPathXmlApplicationContext) context).destroy();
  8. // 完整的加载过程,当然了解的越多越好
  9. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SubBean-Lifecycle.xml");
  10. SubBookClass subBookClass = (SubBookClass) applicationContext.getBean("bookClass");
  11. System.out.println("BookSystemName = " + subBookClass.getBookSystem());
  12. ((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();
  13. }
  14. }

输出完整的结果:

  1. Book Initializing
  2. setBookName: Book name has set.
  3. Book.setBeanName invoke
  4. Book.setBeanFactory invoke
  5. Book.setApplicationContext invoke
  6. MyBeanPostProcessor.postProcessBeforeInitialization
  7. @PostConstruct
  8. Book.afterPropertiesSet invoke
  9. Book.myPostConstruct invoke
  10. MyBeanPostProcessor.postProcessAfterInitialization
  11. Book name = thingking in java
  12. @PreDestory
  13. Book.destory invoke
  14. Book.myPreDestory invoke
  15. ---------------destroy-----------------
  16. Book Initializing
  17. 设置BookSystem 的属性值
  18. Book.setBeanName invoke
  19. SubBookClass.setBeanClassLoader() 方法被调用了
  20. Book.setBeanFactory invoke
  21. SubBookClass.setEnvironment() 方法被调用了
  22. SubBookClass.setEmbeddedValueResolver() 方法被调用了
  23. SubBookClass.setResourceLoader() 方法被调用了
  24. SubBookClass.setApplicationEventPublisher() 方法被调用了
  25. SubBookClass.setMessageSource() 方法被调用了
  26. Book.setApplicationContext invoke
  27. MyBeanPostProcessor.postProcessBeforeInitialization
  28. Book.afterPropertiesSet invoke
  29. Book.myPostConstruct invoke
  30. MyBeanPostProcessor.postProcessAfterInitialization
  31. BookSystemName = Java System
  32. Book.destory invoke
  33. Book.myPreDestory invoke
  34. ---------------destroy-----------------

后记:这篇文章是我翻阅各种书籍和从网上查找资料,包括国外一些网站从而得到的结论,记录下来,但是我没有发现Spring Bean的生命周期(非常详细) 这篇文章中InstantiationAwareBeanPostProcessorAdapter 这个类和工厂后置处理器接口方法,知道的朋友欢迎指教,感谢。

欢迎工作一到五年的Java工程师朋友们加入Java程序员开发: 721575865

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/740630
推荐阅读
相关标签
  

闽ICP备14008679号