浅尝Spring注解开发_Bean生命周期及执行过程
Spring注解开发
浅尝Spring注解开发,基于Spring 4.3.12
包含Bean生命周期、自定义初始化方法、Debug BeanPostProcessor执行过程及在Spring底层中的应用
浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配
浅尝Spring注解开发_Bean生命周期及执行过程
Bean生命周期
了解Bean的生命周期,就可以在Bean声明周期的不同阶段进行自定义的操作,满足更复杂的需求。简单的将Bean生命周期分为三个阶段:Bean创建、初始化、销毁
- 对象创建:单实例在容器启动的时候创建对象,多实例在每次获取的时候创建对象
- 初始化之前:BeanPostProcessor.postProcessBeforeInitialization()
- 初始化:对象创建完成,并赋值好,调用初始化方法
- 初始化之后:BeanPostProcessor.postProcessAfterInitialization()
- [容器创建完成]
- 销毁:单实例在容器关闭的时候销毁,多实例容器不会管理这个bean,容器不会调用销毁方法
现在可以通过下面方法在初始化和销毁时自定义初始化方法来干涉Bean创建过程。
- @Bean()注解参数
- InitializingBean、DisposableBean接口
- @PostConstruct、@PreDestroy注解
- BeanPostProcessor接口
1.@Bean生命周期
通过@Bean指定init-method和destroy-method的初始化方法
先自定义Bean初始化和销毁方法
@Component
public class Car { public Car(){
System.out.println("car constructor...");
}
//现在只是普通方法
public void init(){
System.out.println("car ... init...");
}
//现在只是普通方法
public void detory(){
System.out.println("car ... destory...");
} }
配置进容器
- 通过@Bean注解,在@Bean注册进容器时指定自定义方法
@Configuration
public class MainConfigOfLifeCycle { //@Scope("prototype")多实例,不管销毁
//指定用于初始化和销毁的方法
@Bean(initMethod="init",destroyMethod="destory")
public Car car(){
return new Car();
} }
测试
public class IOCTest_LifeCycle { @Test
public void test01(){
//1、创建ioc容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成..."); //applicationContext.getBean("car");
//关闭容器
applicationContext.close();
} }
输出
//先创建对象
car constructor...
//再自定义初始化方法
car ... init...
//创建完成
容器创建完成...
//关闭时自定义销毁方法
car ... destory...
2.InitializingBean,DisposableBean生命周期
接口,需实现,通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);
实现接口,自定义初始化Bean
public class Cat implements InitializingBean,DisposableBean { public Cat(){
System.out.println("cat constructor...");
} //定义销毁逻辑
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat...destroy...");
} //定义初始化逻辑
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat...afterPropertiesSet...");
} }
配置进容器
- 在@Configuration配置类中使用@Bean
- 或在Bean类上使用@Component然后再配置类上使用@ComponentScan
//配置组件
@Component
public class Cat implements InitializingBean,DisposableBean {
//...
}
//扫描进容器
@ComponentScan("com.xxx.bean")
@Configuration
public class MainConfigOfLifeCycle {
//...
}
测试
public class IOCTest_LifeCycle { @Test
public void test01(){
//1、创建ioc容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成..."); //applicationContext.getBean("car");
//关闭容器
applicationContext.close();
}
}
输出
//注意顺序,每个Bean先构造并初始化,然后才进行下一个Bean,关闭时从内向外
(猫)cat constructor...
(猫)cat...afterPropertiesSet...
(车)car constructor...
(车)car ... init...
//创建完成
容器创建完成...
//关闭时销毁
(车)car ... destory...
(猫)cat...destroy...
3.@PostConstruct生命周期
可以使用JSR250;
@PostConstruct:在bean创建完成并且属性赋值完成之后,来执行初始化方法
@PreDestroy:在容器销毁bean之前通知我们进行清理工作
标注注解,自定义初始化Bean
public class Dog { public Dog(){
System.out.println("dog constructor...");
} //对象创建并赋值之后调用
@PostConstruct
public void init(){
System.out.println("Dog....@PostConstruct...");
} //容器移除对象之前
@PreDestroy
public void detory(){
System.out.println("Dog....@PreDestroy...");
}
}
配置进容器
- 在@Configuration配置类中使用@Bean
- 或在Bean类上使用@Component然后再配置类上使用@ComponentScan
@Component
public class Dog {
//...
}
//扫描进容器
@ComponentScan("com.xxx.bean")
@Configuration
public class MainConfigOfLifeCycle {
//...
}
测试
public class IOCTest_LifeCycle { @Test
public void test01(){
//1、创建ioc容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成..."); //applicationContext.getBean("car");
//关闭容器
applicationContext.close();
} }
输出
//注意顺序,每个Bean先构造并初始化,然后才进行下一个Bean,关闭时从内向外
(猫)cat constructor...
(猫)cat...afterPropertiesSet...
(狗)dog constructor...
(狗)Dog....@PostConstruct...
(车)car constructor...
(车)car ... init...
//创建完成
容器创建完成...
//关闭时销毁
(车)car ... destory...
(狗)Dog....@PreDestroy...
(猫)cat...destroy...
4.BeanPostProcessor
postProcessBeforeInitialization:在创建Bean实例之后,在自定义初始化之前进行调用
postProcessAfterInitialization:在自定义初始化之后进行调用
BeanPostProcessor接口:bean的后置处理器,需实现,在bean初始化前后进行一些处理工作
postProcessBeforeInitialization:在(自定义初始化,如InitializingBean[afterPropertiesSet]、init-method等,就是上面那些自定义初始化方法)初始化之前工作(创建Bean实例之后,在自定义初始化之前)
postProcessAfterInitialization:在(自定义)初始化之后工作
实现后置处理器接口
public class MyBeanPostProcessor implements BeanPostProcessor { //初始化前置方法
//bean:新创建的实例,还未初始化
//beanName:未初始化的Bean名字
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
return bean;
}
//初始化后置方法
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
return bean;
} }
配置进容器
- 在@Configuration配置类中使用@Bean
- 或在Bean类上使用@Component然后再配置类上使用@ComponentScan
@Component
public class MyBeanPostProcessor implements BeanPostProcessor { //...
}
//扫描进容器
@ComponentScan("com.xxx.bean")
@Configuration
public class MainConfigOfLifeCycle {
//...
}
测试
- 这次没有新增的Bean,只配置了一个后置处理器,
- 这个后置处理器会对容器中的Bean起作用,包括上面三种自定义初始化Bean
public class IOCTest_LifeCycle { @Test
public void test01(){
//1、创建ioc容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成..."); //applicationContext.getBean("car");
//关闭容器
applicationContext.close();
} }
输出
//对于每一个Bean都要执行一遍
//1.创建
//2.BeanPostProcessor.postProcessBeforeInitialization()
//3.初始化:对象创建完成,并赋值好,调用初始化方法...
//4.BeanPostProcessor.postProcessAfterInitialization()
//5.销毁 //以其中一个Bean为例:
//构造对象
cat constructor...
//初始化之前
postProcessBeforeInitialization...cat=>com.xxx.bean.Cat@7d68ef40
//使用InitializingBean自定义初始化逻辑
cat...afterPropertiesSet...
//初始化之后
postProcessAfterInitialization...cat=>com.xxx.bean.Cat@7d68ef40
//创建完成
容器创建完成...
//关闭时销毁
cat ... destroy...
BeanPostProcessor原理
bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxxBeanPostProcessor都通过BeanPostProcessor实现
主要方法
populateBean(beanName, mbd, instanceWrapper):给bean进行属性赋值
initializeBean:初始化Bean
{
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);初始化前应用后置处理器
invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);初始化后应用后置处理器
}
遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
一但返回null,跳出for循环
执行过程
了解BeanPostProcessor的执行过程,从AnnotationConfigApplicationContext开始Debug
public class IOCTest_LifeCycle {
@Test
public void test01(){
//1、创建ioc容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成...");
//applicationContext.getBean("car");
//关闭容器
applicationContext.close();
}
}
- 先从创建ioc容器开始,进入
AnnotationConfigApplicationContext()构造方法,执行里面的refresh()方法刷新容器refresh()方法里面有一个finishBeanFactoryInitialization(beanFactory)初始化所有剩余的单实例对象,进入这个方法
- 这个方法最后一步有一个
beanFactory.preInstantiateSingletons()初始化所有单实例Bean,进入这个方法- 触发所有非惰性单例bean的初始化
- 里面调用
getBean(beanName), - 进入
getBean(beanName)里面再调用doGetBean(name,null,null,false) - 进入
doGetBean(name,null,null,false)里面有getSingleton(beanName,new ObjectFactory(){singletonFactory.getObject()})通过匿名内部类调用getObject()
- 此时通过匿名类
getObject()进入下一个调用栈AbstractBeanFactory$1.getObject(),如果是单例,调用createBean(beanName,mbd,args) - 进入
createBean(beanName,mbd,args)调用doCreateBean(beanName,mbd,args)创建一个实例,过程如下- 进入
doCreateBean(beanName,mbd,args),里面调用一个initializeBean(beanName,exposedObject,mbd)初始化方法,这个方法里面就是调用的后置处理器 - 在这个方法上面有
populateBean(beanName,mbd,instanceWrapper)方法,这个方法为Bean属性赋值 - 进入
initializeBean(beanName,exposedObject,mbd),下面有一个invokeInitMethods(beanName,wrappedBean,mbd)执行初始化方法(就是上面的自定义初始化InitializingBean[afterPropertiesSet]、init-method) - 在
invokeInitMethods(beanName,wrappedBean,mbd)[在初始化之前应用 BeanPost 处理器]上面有一个applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)下面有一个applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName)[在初始化之后应用 BeanPost 处理器],作用是在初始化之前应用所有的BeanPostProcessors在初始化之后应用所有的BeanPostProcessors
- 进入
- 进入
applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)- 里面有
getBeanPostProcessors()找到所有BeanPostProcessors遍历,包括Spring系统的BeanPostProcessor如ApplicationContextAwareProcessor、ConfigurationClassPostProcessor等,然后才是自定义的MyBeanPostProcessor,依次执行beanProcessor.postProcessBeforeInitialization() - 如果有执行返回null,就结束遍历,返回null,后面的处理器就不执行了(不应用后续的
BeanPostProcessors了)
- 里面有
调用栈
获取单例

创建实例Bean

给Bean属性赋值和初始化Bean

完整流程
Spring底层对 BeanPostProcessor 的使用;

- 由上图可以看到,Spring中的BeanPostProcessor在实例化过程处于的位置,BeanPostProcessor接口有两个方法需要实现:postProcessBeforeInitialization和postProcessAfterInitialization
- 前者在实例化及依赖注入完成后、在任何初始化代码(比如配置文件中的init-method)调用之前调用;后者在初始化代码调用之后调用。
BeanPostProcessor在Spring底层的使用
许多注解底层都是基于BeanPostProcessor
BeanPostProcessor接口实现类

向组件中注入IoC容器
在Bean创建过程中,初始化之前,判断是否实现了某Aware接口,如果实现了,就向Bean中注入ApplicationContext容器
向Bean中注入IoC容器
实现ApplicationContextAware接口,声明属性,赋值,就可以在组件中使用Ioc容器
@Component
public class Dog implements ApplicationContextAware { //声明IoC容器
private ApplicationContext applicationContext; public Dog(){
System.out.println("dog constructor...");
} //对象创建并赋值之后调用
@PostConstruct
public void init(){
System.out.println("Dog....@PostConstruct...");
} //容器移除对象之前
@PreDestroy
public void detory(){
System.out.println("Dog....@PreDestroy...");
} //把applicationContext IoC容器赋值给属性
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
this.applicationContext = applicationContext;
}
}
原理是通过
ApplicationContextAwareProcessor实现ApplicationContextAwareProcessor实现了BeanPostProcessor接口
在
postProcessBeforeInitialization()方法中- 在Bean初始化之前,判断Bean是否实现了
ApplicationContextAware接口,或其他Aware接口 - 如果实现了,就调用
invokeAwareInterfaces(bean)给Bean注入值 - 判断Bean是什么类型Aware,将Bean转成对应类型调用
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext)注入IoC容器 - 于是就到了上面实现的接口的未实现方法中
- 在Bean初始化之前,判断Bean是否实现了
数据校验
BeanValidationPostProcessor也实现了BeanPostProcessor接口- 在Bean创建完赋值后,同样调用
postProcessBeforeInitialization()方法,进行数据校验postProcessBeforeInitialization(){doValidate(bean)}postProcessAfterInitialization(){doValidate(bean)}
自定义初始化注解
- Bean初始化有一种方法是使用
@PostConstruct注解,也是通过BeanPostProcessor实现 InitDestroyAnnotationBeanPostProcessor处理@PostConstruct和@PreDestroy注解- 在
postProcessBeforeInitialization()中找到Bean的生命周期注解所标注的方法,如initMethods、destroyMethods - 找到之后就执行注解标注的初始化方法
metatata.invokeInitMethods(bean,beanName)和element.invoke(target),利用反射执行。
- 在
自动注入注解@Autowired
- 为什么@Autowired能够自动注入值,是通过这个
AutowiredAnnotationBeanPostProcessor实现BeanPostProcessors接口 - 在对象创建完之后,处理标注
@Autowired标注的所有属性进行注入值
浅尝Spring注解开发_Bean生命周期及执行过程的更多相关文章
- 浅尝Spring注解开发_AOP原理及完整过程分析(源码)
浅尝Spring注解开发_AOP原理及完整过程分析(源码) 浅尝Spring注解开发,基于Spring 4.3.12 分析AOP执行过程及源码,包含AOP注解使用.AOP原理.分析Annotation ...
- 浅尝Spring注解开发_Servlet3.0与SpringMVC
浅尝Spring注解开发_Servlet 3.0 与 SpringMVC 浅尝Spring注解开发,基于Spring 4.3.12 Servlet3.0新增了注解支持.异步处理,可以省去web.xml ...
- 浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配
Spring注解开发 浅尝Spring注解开发,基于Spring 4.3.12 包含自定义扫描组件.自定义导入组件.手动注册组件.自动注入方法和参数.使用Spring容器底层组件等 配置 @Confi ...
- Spring注解开发系列Ⅲ --- 生命周期
Bean的生命周期 Spring Bean 的生命周期在整个 Spring 中占有很重要的位置,掌握这些可以加深对 Spring 的理解. 首先看下生命周期图: 再谈生命周期之前有一点需要先明确: S ...
- Spring的Bean的生命周期方法执行顺序测试
通过一个简单的Maven工程来演示Spring的Bean生命周期函数的执行顺序. 下面是工程的目录结构: 直接贴代码: pom.xml文件内容: <?xml version="1.0& ...
- Servlet学习(一)——Servlet的生命周期、执行过程、配置
1.什么是Servlet Servlet 运行在服务端的Java小程序,是sun公司提供一套规范(接口),用来处理客户端请求.响应给浏览器的动态资源.但servlet的实质就是java代码,通过jav ...
- Vue生命周期的执行过程(面试必备) 极简版
最近准备面试,临时抱佛脚的来回顾一下vue相关的面试题,当然这是不对的,平时还是要努力呀,走起: 1.创建vue实例,Vue(); 2.在创建Vue实例的时候,执行了init(),在init过程中首先 ...
- Spring注解开发_Spring容器创建概述
浅尝Spring注解开发_Spring容器创建概述 浅尝Spring注解开发,基于Spring 4.3.12 概述Spring容器创建的过程,包括12个方法的执行 浅尝Spring注解开发_自定义注册 ...
- Spring注解开发-全面解析常用注解使用方法之生命周期
本文github位置:https://github.com/WillVi/Spring-Annotation/ 往期文章:Spring注解开发-全面解析常用注解使用方法之组件注册 bean生命周期 ...
随机推荐
- 接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?
接口可以继承接口,而且支持多重继承.抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类.
- Redis 支持的 Java 客户端都有哪些?官方推荐用哪个?
Redisson.Jedis.lettuce 等等,官方推荐使用 Redisson.
- spring-boot-learning-事务处理
事务处理的重要性: 面对高井发场景, 掌握数据库事务机制是至关重要的,它能够帮助我们在一定程度上保证数据的一致性,并且有效提高系统性能,避免系统产生岩机,这对于互联网企业应用的成败是至关重要的. 以 ...
- Redis 是单进程单线程的?
Redis 是单进程单线程的,redis 利用队列技术将并发访问变为串行访问,消 除了传统数据库串行控制的开销.
- CAN总线系列讲座第五讲——CAN总线硬件电路设计
CAN总线系列讲座第五讲--CAN总线硬件电路设计一 实战学习背景 CAN总线节点的硬件构成方案有两种,其中的方案:(1).MCU控制器+独立CAN控制器+CAN收发器.独立CAN控制器如SJA10 ...
- safari浏览器fixed后,被软键盘遮盖的问题—【未解决】
safari浏览器fixed后,被软键盘遮盖的问题,已经有好多人问相关的问题,应该是问的角度不一样,还的再次提出咯. 问题描述 测试环境:ios 10.2/10.3 简单来说就是在html5页面中底部 ...
- 记一次用mpvue框架搭建的小程序
介绍 mpvue (github 地址请参见)是一个使用 Vue.js 开发小程序的前端框架.框架基于 Vue.js 核心,mpvue 修改了Vue.js 的 runtime 和 compiler 实 ...
- python-爬楼梯
[题目描述] 假设一段楼梯共n(n>1)个台阶,小朋友一步最多能上3个台阶,那么小朋友上这段楼梯一共有多少种方法. [练习要求]请给出源代码程序和运行测试结果,源代码程序要求添加必要的注释. [ ...
- new String比字符串池浪费空间,为什么要用它?
对于下面程序中:ss0 = new String( "hello" );是用new()来新建对象的,存于堆中.每调用一次就会创建一个新的对象.当然从节省空间的角度来讲,肯定不如st ...
- scss使用方法以及相关内容
我们平时都称之为 Sass,其实可分成sass和scss, 其中Sass 是以严格的缩进式语法规则来书写,不带大括号({})和分号(;),以".sass"后缀为扩展名:而 SCSS ...