Spring5源码分析之Bean生命周期
Spring Bean生命周期的构成
Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
- Bean自身的方法: 这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法
- Bean级生命周期接口方法: 这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法
- 容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
- 工厂后处理器接口方法: 这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
生命周期
创建 ----> 初始化 ---> 销毁
1. 实例化对象
2. setter注入,执行Bean的属性依赖注入
3. BeanNameAware的setBeanName(), 如果实现该接口,则执行其setBeanName 方法
4.BeanFactoryAware的setBeanFactory(), 如果实现该接口,则执行其setBeanFactory方法
5. BeanPostProcessor的processBeforeInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processBeforeInitialization() 方法
综上:
// 后置处理器
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 执行自定义init方法之前处理
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println( "3.[BeanPostProcessor] ---> postProcessBeforeInitialization 执行init方法[之前]处理") ;
return bean;
} /**
* 执行自定义init方法之后处理
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println( "5.[BeanPostProcessor] ---> postProcessAfterInitialization 执行init方法[之后]处理") ; return bean;
}
}
6. InitializingBean的afterPropertiesSet(), 如果实现了该接口,则执行其afterPropertiesSet()方法。Bean定义文件中定义init-method
7.BeanPostProcessors的processAfterInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processAfterInitialization()方法
8.DisposeablebBean的 destory(),在容器关闭时,如果Bean实现了这个接口,则执行他的destory()方法
9. Bean定义文件中定义destroy-method,在容器关闭时,可以在Bean定义文件中使用“destory-method”定义的方法
注:
1. 单例默认时在容器被加载时候会初始化
2. 多例在每次获取Bean的对象时候才会去初始化
bean 初始化 指的就是对象已经创建里面所有的set方法都已经执行完毕了。 指定方法执行
@Bean(initMethod , destory) 指定初始化和销毁方法 同时在bean中创建这两个方法
init是在构造方法之前还是之后执行? 无参构造! 对象先创建完成后才进行初始化!所以先执行无参构造函数!
补充到上面的过程:
Bean的创建(执行构造函数) --> 初始化(自定义init方法) --> 销毁
调用close() 方法销毁单例对象
注意:IOC容器使用Map结合存储对象,clear() 清除对象
看源码:

进入查看:

继续点击查看:

看第一个:

持续跟进后就是 集合的 clear 方法了

我们可以通过实现某些类 去进行初始化的操作!
开发使用的方式:
方法一: 通过@Bean指定init-method 和 destory-method
方法二: 通过让Bean实现InitializingBean(定义初始化逻辑), DisposableBean(定义销毁逻辑)
方法三: 使用JSR250(Java规范,不是Spring的): @PostConstruct: 在Bean创建完成并且赋值完成,来执行初始化方法。 @PreDestory: 在容器销毁Bean之前通知我们进行清理工作
方法二:
Bean:
@Component
public class LifeBean implements InitializingBean, DisposableBean { //构造函数
public LifeBean() {
System.out.println("LifeBean Constructor");
} /** 接口InitializingBean的方法
* //解释 对象有创建 肯定也有给属相赋值的过程!,对象赋值完毕以后才执行该方法 即: (afterPropertiesSet)中文:set方法都走完了时候执行该方法
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
//等同于 @Bean(init =" ")
//解释 对象有创建 肯定也有给属相赋值的过程!,对象赋值完毕以后才执行该方法
System.out.println("LifeBean ********> 【InitializingBean.afterPropertiesSet】 ");
} /**
* 接口DisposableBean 的方法
* @throws Exception
*/
@Override
public void destroy() throws Exception {
System.out.println("LifeBean ********>【DisposableBean.destroy】");
}
}
配置和扫包
@Configuration
@ComponentScan("com.toov5.config.beanTest.entity")
public class MyConfig { }
启动测试:
public class test {
public test(){
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext1 = new AnnotationConfigApplicationContext("com.toov5.config");
applicationContext1.close();
// System.out.println(applicationContext1);
}
}

方法三
注解代替了接口:
Bean:
@Component
public class LifeBean { //构造函数
public LifeBean() {
System.out.println("LifeBean Constructor");
}
@PostConstruct
public void afterPropertiesSet() throws Exception {
//等同于 @Bean(init =" ")
//解释 对象有创建 肯定也有给属相赋值的过程!,对象赋值完毕以后才执行该方法
System.out.println("LifeBean ********> 【InitializingBean.afterPropertiesSet】 ");
} @PreDestroy
public void destroy() throws Exception {
System.out.println("LifeBean ********>【DisposableBean.destroy】");
}
}
效果是一样的:

几个重要的Aware接口:
1. ApplicationContextAware
过滤器中,不可以使用注解方式获取Bean对象。 做法: 单独获取上下文ApplicationContext
后置处理器,实现对Bean初始化增强功能
@Component
public class MyApplicationContext implements ApplicationContextAware {
//开发时候经常做成全局的 进行使用
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
LifeBean lifeBean = applicationContext.getBean("lifeBean", LifeBean.class);
System.out.println("result————————————————————"+lifeBean.toString());
}
}
运行后:结果是没问题的

问题: Spring底层中为什么能够实现ApplicationContextAware接口,就能够拿到ApplicationContext。
2. BeanNameAware 与 BeanFactoryAware
Bean
@Component
public class LifeBean01 implements BeanNameAware, BeanFactoryAware { public LifeBean01() {
System.out.println("LifeBean01 对象实例化完成");
} @Override
public void setBeanName(String s) {
System.out.println("beanName:"+s);
} @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("beanFactory:"+ beanFactory);
}
}
配置类:
@Configuration
@ComponentScan("com.toov5.config.beanTest.entity")
public class MyConfig { }
测试:
public class test {
public test(){
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext1 = new AnnotationConfigApplicationContext("com.toov5.config");
applicationContext1.close();
// System.out.println(applicationContext1);
}
}

IOC容器初始化到哪里独享都是循环遍历getBean方法。
getSingleton(beanName) 先查询缓存有没有,看下之前有没有创建过
Spring Bean生命周期中的后置处理器: BeanPostProcessor接口
从源码可以看到是 可以在 init之前或者之后进行一系列的操作的
加上上面的那几个接口一起展示下:
后置处理器,单独处理到别的bean里面去, 其他的bean(Spring 自带的都会走这个方法了)。
init 之前之后,通过后置处理器对bean的初始化进行增强。 可以做bean耗时统计,日志打印等等。
Bean:
@Component
public class LifeBean01 implements BeanNameAware, BeanFactoryAware, InitializingBean { public LifeBean01() {
System.out.println("1. -----------------》LifeBean01 对象实例化完成");
} @Override
public void setBeanName(String s) {
System.out.println("2. -----------------》对象beanName:"+s);
} @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("3. -----------------》beanFactory:"+ beanFactory);
} @Override
public void afterPropertiesSet() throws Exception {
System.out.println("5. -----------------》 bean init 方法执行");
}
}
后置处理器:
// 后置处理器
@Component
public class MyBeanPostProcessor implements BeanPostProcessor{
/**
* 执行自定义init方法之前处理
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println( beanName + "==========> 执行init方法[之前]处理");
return bean;
} /**
* 执行自定义init方法之后处理
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName +"==========>执行init方法[之后]处理");
return bean;
}
}
配置类:
@Configuration
@ComponentScan("com.toov5.config.beanTest.entity")
public class MyConfig { }
测试:
public class test {
public test(){
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext1 = new AnnotationConfigApplicationContext("com.toov5.config");
// applicationContext1.close();
// System.out.println(applicationContext1);
}
}
结果:

生命周期流程图:

描述:
1.实例化对象 (可以反射, 可以new)
2. 给对象属性赋值
3. 检查是否有Aware依赖,如果有上述的哪些,就进行执行。
总结: 重点无非就是 Aware 和 后置处理器
从源码中看 setApplicationContext() 方法是在前置获取的。 通过postProcessBefore前置,里面的默认方法获取到上下文对象。
总结:
后置处理器:
@Component
public class LifeBean implements BeanNameAware, BeanFactoryAware ,
InitializingBean, DisposableBean { @Override
public void setBeanName(String s) {
System.out.println("1.[BeanNameAware] ---> setBeanName");
} @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("2.[BeanFactoryAware] ---> setBeanFactory");
} @Override
public void afterPropertiesSet() throws Exception {
System.out.println("4.[InitializingBean] ---> afterPropertiesSet");
} @Override
public void destroy() throws Exception {
System.out.println("6.[DisposableBean] ---> distory" );
}
}
Bean:
// 后置处理器
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 执行自定义init方法之前处理
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println( "3.[BeanPostProcessor] ---> postProcessBeforeInitialization 执行init方法[之前]处理") ;
return bean;
} /**
* 执行自定义init方法之后处理
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println( "5.[BeanPostProcessor] ---> postProcessAfterInitialization 执行init方法[之后]处理") ; return bean;
}
}
配置:
@Configuration
@ComponentScan("com.spring.test")
public class config { }
测试
public class test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext1 = new AnnotationConfigApplicationContext(config.class);
applicationContext1.close();
}
}

Spring5源码分析之Bean生命周期的更多相关文章
- Spring5源码分析(1)设计思想与结构
1 源码地址(带有中文注解)git@github.com:yakax/spring-framework-5.0.2.RELEASE--.git Spring 的设计初衷其实就是为了简化我们的开发 基于 ...
- Spring 源码分析之 bean 依赖注入原理(注入属性)
最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...
- Spring源码分析之Bean的创建过程详解
前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...
- Spring Ioc源码分析系列--Bean实例化过程(二)
Spring Ioc源码分析系列--Bean实例化过程(二) 前言 上篇文章Spring Ioc源码分析系列--Bean实例化过程(一)简单分析了getBean()方法,还记得分析了什么吗?不记得了才 ...
- dubbo源码分析1-reference bean创建
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- dubbo源码分析2-reference bean发起服务方法调用
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- dubbo源码分析3-service bean的创建与发布
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- Spring Ioc源码分析系列--Bean实例化过程(一)
Spring Ioc源码分析系列--Bean实例化过程(一) 前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对 ...
- 【Spring源码分析】Bean加载流程概览
代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...
随机推荐
- Caused by: java.nio.charset.MalformedInputException: Input length = 1
java.lang.IllegalStateException: Failed to load property source from location 'classpath:/applicatio ...
- 基于 Redis 实现简单的分布式锁
摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...
- Flask - 四剑客 | templates | 配置文件 | 路由系统 | CBV
Flask框架简介 说明:flask是一个轻量级的web框架,被称为微型框架.只提供了一个高效稳定的核心,其它全部通过扩展来实现.意思就是你可以根据项目需要进行量身定制,也意味着你需要不断学习相关的扩 ...
- Codeforces Round #604 (Div. 2) A,B,C【D题待补】
思路:直接暴力判断就OK了 #include<bits/stdc++.h> using namespace std; #define int long long signed main() ...
- php自定义函数之变量函数
在之前的变量部份,我们学习了可变变量.可变函数仅仅是可变变量的一个变种.变形表达.大理石平台价格表 可变函数,我们也会称呼为变量函数.简单回顾一下之前的知识点: <?php $hello = ...
- WebAPI学习
WebAPI概述 今天的web计算平台包含了广泛的功能,其中的大部分均可以通过API(应用程序编程接口)访问. web平台归为6个基本设施,都会用到webapi,包括存储服务.消息服务.计算服务.信息 ...
- aix 10代oracle zabbix2.4.4 日志监控
同一类型的监控项,zabbix 2.4的客户端也支持日志监控,可是在参数个数上有问题,如果把所有参数都放满,监控项会提示too mant parameters,无法 生效取数据, 对于不同的正则式.m ...
- 洛谷 P2872 [USACO07DEC]道路建设Building Roads 题解
P2872 [USACO07DEC]道路建设Building Roads 题目描述 Farmer John had just acquired several new farms! He wants ...
- 我们使用 Kafka 生产者在发消息的时候我们关注什么(Python 客户端 1.01 broker)
之前使用 Kafka 的客户端消费者比较多一点,而且也是无脑订阅使用也没有深入了解过具体的参数.总的来说使用不够细节. 这次公司项目活动期间暴露非常多的问题,于是有了这篇文章. 首先我们来拆解一下 K ...
- golang go程和出让时间片
golang go程和出让时间片 func main() { go func(){ //创建一个子go程 ;i<;i++{ fmt.Println("--------fuck U--- ...