完整的生命周期(牢记):

1.spring容器准备

2.实例化bean

3.注入依赖关系

4.初始化bean

5.使用bean

6.销毁bean

Bean的完整生命週期可以認為是從容器建立初始化Bean開始,直到Spring容器關閉。
事實上,在Bean被初始化建立之前,容器級別的介面方法也會對Bean產生影響,因此這裡把這兩個事件也加進來了。

各种接口方法分类

将上述流程分为三类:
1.Bean自身的方法,如Bean自身的构造函数、Setter方法设置属性以及<bean>的init-method和destroy-method所指定的初始化和销毁时的方法。
2.Bean级别生命周期接口方法,需要bean自身实现接口的方法,如BeanNameAware、BeanFactoryAware、InitializingBean和DisposableBean(例:如果这个Bean实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的是Spring配置文件中Bean的ID)
3.容器级别生命周期接口,即 后处理器 。此类一般不由Bean本身实现,独立于Bean,实现这些接口的类以容器附加装置的形式注册到Spring容器中。特点是:当Spring容器创建任何Bean的时候,这些后处理器都会执行并发生作用,它们的影响是全局性的。 如: InstantiationAwareBeanPostProcessor和BeanPostProcessor 接口。
后处理器在实例化bean的时候就实例化了,如BeanPostProcessor在实例化bean之前已经实例化,但在初始化bean的时候才被使用,见上图 区别:
第一类别,目标Bean关注自身方法,不需要实现任何接口。
第二类别,目标Bean需要实现相应的接口,有耦合。
第三类别,修改和目标Bean没有关系,需要额外的类实现接口,并注册到Spring容器中。
Bean生命周期   (分为BeanFactory和ApplicationContext两种情况)

Spring框架中,一旦把一个Bean纳入Spring IOC容器之中,这个Bean的生命周期就会交由容器进行管理,一般担当管理角色的是BeanFactory或者ApplicationContext

如图,ApplicationContext继承自BeanFactory,因而提供BeanFactory所有的功能,除此之外还继承了其他接口,所以

ApplicationContext包还提供了以下的功能: (链接:https://www.zhihu.com/question/38597460/answer/279813125)
1.MessageSource, 提供国际化的消息访问
2.资源访问,如URL和文件
3.事件传播
4.载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
5.其它区别
1).BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。
2).BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册

以下都是不包含(1.spring容器准备)的生命周期
 
BeanFactory中的Bean的生命周期

图中步骤编号对应生命周期:

1.spring容器准备:图中未包含

2.实例化bean:1,2,3,4

3.注入依赖关系:5,6,7

4.初始化bean:8,9,10,11

5.使用bean:12

6.销毁bean:13,14

见上图,对于prototype作用域的Bean,Spring容器仅仅负责创建,当容器创建了Bean实例之后,Bean实例完全交给客户端代码管理,容器不再跟踪其生命周期。每次客户端请求prototype作用域的Bean时,Spring都会产生一个新的实例,Spring容器无法知道它曾经创造了多少个prototype作用域的Bean,也无从知道这些prototype作用域的Bean什么时候才会销毁。因此,Spring无法管理prototype作用域的Bean。

  1. 当调用者通过getBean(beanName)向容器请求某一个Bean时,如果容器中注册了 InstantiationAwareBeanPostProcessor接口,就会在实例化Bean之前,调用接口的postProcessBeforeInstantiation()方法。
  2. 根据配置情况调用Bean构造函数或工厂方法实例化Bean
  3. 调用postProcessAfterInstantiation()方法,对已经实例化的对象进行一些加工
  4. 如果Bean配置了属性信息,这一步将配置值设置到Bean对应的属性中,在设置每个属性之前将先调用postProcessPropertyValues()方法
  5. 调用Bean的属性设置方法设置属性
  6. 如果实现了BeanNameAware接口,将调用setBeanName()接口方法,将配置文件中该Bean对应的名称设置到Bean中
  7. 如果实现了BeanFactoryAware接口,通过setBeanFactory()方法,将BeanFactory()容器实例设置到Bean
  8. 如果BeanFactory装配了BeanPostProcessor后处理器,将调用Object postProcessBeforeInitialization(Object bean,String beanName)接口方法对Bean进行加工操作。bean为当前正在处理的Bean,返回加工后的Bean。为容器提供对Bean进行后续加工处理的切入点,AOP,动态代理等功能都是通过BeanPostProcessor实施的。
  9. 如果Bean实现了InitializingBean接口,将调用接口的afterPropertiesSet()方法
  10. 执行<bean>中init-method属性定义的初始化方法
  11. BeanPostProcessor后处理器的 postProcessAfterInitialization再次对bean进行加工
  12. 如果scope='prototype',就返回bean给调用者,调用者负责bean后续生命的管理,Spring不再管理这个Bean的生命周期。如果作用范围是"singleton",Bean将放入SpringIoC容器缓存池中,并将bean引用返回,Spring继续对这些Bean进行后续的生命管理。
  13. 对于singleton的bean,容器关闭时会触发Spring对Bean后续生命周期的管理。如果Bean实现了DisposableBean接口,将调用接口的destory()方法,可以在此编写释放资源,记录日志等操作。(dispose处理)
  14. 调用<bean>的destroy-method属性指定的方法进行bean的销毁
 
Bean的完整生命周期从Spring容器实例化开始,直到最终销毁Bean。大致分为4类操作:
  • Bean自身的方法:如调用Bean构造函数实例化Bean,调用Setter设置Bean的属性值及通过<bean>的init-method和destroy-method所指定的方法
  • Bean级生命周期接口方法:BeanNameAware,BeanFactoryAware,InitializingBean和DisposableBean,接口方法由Bean类直接实现
  • 容器级生命周期接口:InstantiationAwareBeanPostProcesser和BeanPostProcessor这两个接口实现,一般称为"后处理器"。实现类以容器附加装置的形式注册到Spring容器中,通过接口反射为Spring容器扫描识别。Spring容器创建任何Bean时,这些后处理器都会发生作用,影响是全局性的。
  • 工厂后处理器接口方法:AspectJWeavingEnabler,CustomAutowireConfigurer,ConfigurationClassPostProcessor等方法。容器级,在应用上下文装配配置文件后立即调用。
 
Bean级生命周期接口处理Bean个性化的问题
容器级生命周期接口处理Bean共性化的问题
InstantiationAwareBeanPostProcessor其实是BeanPostProcessor接口的子接口,Spring为其提供了一个适配器类InstantiationAwareBeanPostProcessorAdapter,可以方便的扩展该类。
 
main():手动注册
ResourceLoader resourceLoader = new PathMatchingResourcePatternResolver();
Resource resource = resourceLoader.getResource("classpath:spring/SpringContext.xml"); BeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((DefaultListableBeanFactory) beanFactory);
reader.loadBeanDefinitions(resource); //向容器中注册BeanPostProcessor后处理器
((ConfigurableBeanFactory) beanFactory).addBeanPostProcessor(new MyBeanPostProcessor());
((ConfigurableBeanFactory) beanFactory).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor()); Car car = (Car) beanFactory.getBean("car");
Car car1 = (Car) beanFactory.getBean("car");
System.out.println(car == car1);//默认单例,两次获取的car对象一样
car.carRun(); //关闭容器
((DefaultListableBeanFactory) beanFactory).destroySingletons();
 在对beanfactory注册BeanPostProcessor后处理器时,将beanfactory强制类型转换为了ConfigurableBeanFactory。由于addBeanPostProcessor()方法是在ConfigurableBeanFactory接口中定义的。多个后处理器注册时,实际调用顺序和注册顺序无关,多后处理器需要实现Ordered接口。
    
    上面获取了两次car对象,如果是prototype范围,则生命周期会被执行两次,因为每次都返回的新对象实例。
思考:
    通过Bean级别的生命周期接口对Bean进行控制,虽然让Bean具有了更细致的生命周期阶段,但是让Bean和Spring框架紧密结合在一起了。通常通过init-method和destroy-method属性配置的方式来为Bean指定初始化和销毁的方法。
    Spring还提供了一个Bean后置处理器,InitDestroyAnnotationBeanPostProcessor.负责对标注了@PostConstruct,@PreDestroy的Bean进行处理,在bean初始化后及销毁前执行相应的逻辑(在ApplicationContext中,已经默认装配了该处理器)。
    如果bean希望在运行期获知在配置文件中的Bean名称,可以简单地将名称作为属性注入
    BeanProcessor接口十分特殊,它不要求Bean去继承,可以完全像插件一样注册到Spring容器中。AOP等功能就是基于此实现的。    
 
ApplicationContext中Bean的生命周期  

Bean在应用上下文中的生命周期和在BeanFactory中的生命周期类似,不同的是,如果Bean实现了org.springframework.context.ApplicationContextAware接口,则会增加一个调用方法setApplicationContext()的步骤。

 
      如果配置文件中声明了工厂后处理器接口BeanFactoryPostProcessor的实现类,在初始化Bean实例之前会调用这些BeanFactoryPostProcessor对配置信息进行加工处理。Spring框架提供了多个工厂后处理器,CustomEditorConfigurer,PopertyPlaceholderConfigurer等。
                 工厂后处理器是容器级的,仅在应用上下文初始化时调用一次,目的是完成一些配置文件的加工处理工作。
     
     
ApplicationContext Bean生命周期流程:

(总结:)

初始化阶段,先调用 InitializingBean接口的afterPropertiesSet()方法,再调用init-method属性定义的初始化方法。与销毁阶段不同的是,初始化阶段外面包裹了一层BeanPostProcessor后处理器的postProcessBeforeInitialization()和postProcessAfterInitialization()方法

销毁阶段,先调用 DisposableBean接口的destory()方法,再调用destory-method属性定义的销毁方法

BeanFactory和ApplicationContext区别就在于BeanFactory手动注册:

ApplicationContext会利用Java反射机制自动识别出配置文件中定义的BeanPostProcesser,InstantiationAwareBeanPostProcessor和BeanFactoryPostProcessor,并自动将它们注册到应用上下文中。而BeanFactory需要手动addBeanPostProcessor()去进行注册。

调用ApplicationContextAware接口的setApplicationContext()方法,传入该BeanApplicationContext,这样该Bean就获得了自己所在的ApplicationContext,不用再手动注册了

            ApplicationContext Bean生命周期流程

流程

 
                BeanFactory Bean生命周期流程
 
 
代码示例见另一篇:https://i.cnblogs.com/EditPosts.aspx?postid=10215041&update=1
 
 
 https://super-wangj.iteye.com/blog/2386440
http://lvsongsong.top/article/html/94f196c8978243c6905ca5267cf20663
https://zsr.github.io/2017/05/05/Spring-Bean-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/

【不懂】spring bean生命周期的更多相关文章

  1. spring bean 生命周期和 ? 作用域? spirng bean 相互依赖? jvm oom ? jvm 监控工具? ThreadLocal 原理

    1. spring bean 生命周期 1. 实例化一个bean ,即new 2. 初始化bean 的属性 3. 如果实现接口 BeanNameAware ,调用 setBeanName 4. Bea ...

  2. Spring点滴四:Spring Bean生命周期

    Spring Bean 生命周期示意图: 了解Spring的生命周期非常重要,我们可以利用Spring机制来定制Bean的实例化过程. -------------------------------- ...

  3. Spring Bean 生命周期之destroy——终极信仰

    上一篇文章 Spring Bean 生命周期之我从哪里来 说明了我是谁? 和 我从哪里来? 的两大哲学问题,今天我们要讨论一下终极哲学我要到哪里去? 初始化 Spring Bean 有三种方式: @P ...

  4. 常见问题:Web/Servlet生命周期与Spring Bean生命周期

    Servlet生命周期 init()初始化阶段 Servlet容器加载Servlet(web.xml中有load-on-startup=1;Servlet容器启动后用户首次向Servlet发请求;Se ...

  5. 大厂高频面试题Spring Bean生命周期最详解

    Spring作为当前Java最流行.最强大的轻量级框架.Spring Bean的生命周期也是面试高频题,了解Spring Bean周期也能更好地帮助我们解决日常开发中的问题.程序员应该都知道Sprin ...

  6. Spring Bean生命周期,好像人的一生。。

    大家好,我是老三,上节我们手撸了一个简单的IOC容器五分钟,手撸一个Spring容器!,这节我们来看一看Spring中Bean的生命周期,我发现,和人的一生真的很像. 简单说说IoC和Bean IoC ...

  7. 睡前聊一聊"spring bean 生命周期"

    spring bean 生命周期=实属初销+2个常见接口+3个Aware型接口+2个生命周期接口 实属初销:spring bean生命周期只有四个阶段,即实例化->属性赋值->初始化-&g ...

  8. Spring Bean 生命周期2

    在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象使用Sin ...

  9. Spring bean 生命周期验证

    一.从源码注释看bean生命周期 从JDK源码上看,BeanFactory实现类需要支持Bean的完整生命周期,完整的初始化方法及其标准顺序(格式:接口 方法)为: 1.BeanNameAware s ...

随机推荐

  1. bzoj 1103 : [POI2007]大都市meg (树链剖分+线段树)

    Description 在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Mary也开始骑着摩托车传递邮件了.不过,她经常回忆起以前在乡间漫步的情景.昔日,乡下有依次编号为1..n ...

  2. nginx+php使用open_basedir限制站点目录防止跨站

    以下三种设置方法均需要PHP版本为5.3或者以上.方法1)在Nginx配置文件中加入 fastcgi_param PHP_VALUE "open_basedir=$document_root ...

  3. 【HDU-6146】Pokémon GO(dp)

    百度之星2017复赛1003 HDU-6146 Pokémon GO 题意 两行n列,只能到相邻格子,可以斜着.求遍历的方案数. 题解 dp[i]从一个点出发遍历长度i最后回到这一列的方案数 dp2[ ...

  4. 【BZOJ4543】Hotel加强版(长链剖分)

    [BZOJ4543]Hotel加强版(长链剖分) 题面 BZOJ,没有题面 洛谷,只是普通版本 题解 原来我们的\(O(n^2)\)做法是设\(f[i][j]\)表示以\(i\)为根的子树中,距离\( ...

  5. 添加默认安全组规则-openstack

    if [ "$1" ] ;then neutron security-group-rule-create --direction ingress --ethertype ipv4 ...

  6. [NOI2015]寿司晚宴(状压dp)

    为了庆祝NOI的成功开幕,主办方为大家准备了一场寿司晚宴.小G和小W作为参加NOI的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了n−1种不同的寿司,编号1,2,3,⋯,n-1,其中第种 ...

  7. centos7/rhel7安装较高版本ruby2.2/2.3/2.4+

    环境需求: 在Centos7.3中,通过yum安装ruby的版本是2.0.0,但是如果有些应用需要高版本的ruby环境,比如2.2,2.3,2.4...那就有点麻烦了,譬如:我准备使用redis官方给 ...

  8. 解决使用jedis连接是报DENIED Redis is running in protected mode错误

    DENIED Redis is running in protected mode because protected mode is enabled, no bind address was spe ...

  9. The 2018 ACM-ICPC Asia Qingdao Regional Contest

    The 2018 ACM-ICPC Asia Qingdao Regional Contest 青岛总体来说只会3题 C #include<bits/stdc++.h> using nam ...

  10. 论一个蒟蒻的脑子里可以有多少坑(貌似咕了……目前更新保持在noip阶段)

    就是错题整理了,其实也会把一些不该犯的失误整进来. 其实之前一直拖着不想写,直到某次模拟赛,看错了2道题,顺便爆了一道题的int(没错第一个点就会爆)之后爆零了,吓得我赶紧把这篇博客搞出来了..... ...