简记Bean生命周期(xml方式与注解方式)
什么是Bean
- 官网的解释是:在 Spring 中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是一个由Spring IoC容器实例化、组装和管理的对象。
1. xml方式
1.1. 在 Spring中有两种bean: 普通Bean 和 工厂Bean
- 普通bean:配置文件中定义bean类型就是返回类型
<bean id="user" class="com.demo.pojo.User">
</bean>
*工厂bean(FactoryBean):配置文件中定义bean类型可以和返回类型不同
(1)创建类,让这个类作为工厂bean,实现接口FactoryBean
(2)实现接口里的方法,在实现的方法里定义返回的bean类型
1.1.1. FactoryBean举例代码
// 设置Mybean返回的类型为Course
public class MyBean implements FactoryBean<Course> {
@Override
/**
* 返回bean实例;自定义返回bean
*/
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("abc");
return course;
}
@Override
/**
* 返回bean类型
*/
public Class<?> getObjectType() {
return Course.class;
}
@Override
/**
* 判断是否为单例
*/
public boolean isSingleton() {
return false;
}
}
#####################################################################
配置文件中配置
<bean id="mybean" class="com.demo.factorybean.MyBean"></bean>
1.2. Bean作用域
- 在Spring中可以设置创建bean实例是单实例还是多实例 (单实例对象地址值相同)
- 在Spring中,默认情况下创建的bean实例为单实例
- 在Spring配置文件中的bean标签中有属性(scope)用于设置单实例还是多实例
1.2.1. 举例代码
public class Books {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
public void testbooks() {
System.out.println( "books{" +
"list=" + list +
'}');
}
}
##########################################
xml中配置:
<util:list id="booksList">
<value>java修炼之路</value>
<value><![CDATA[
<<java手册>>
]]></value>
<value>《jvm调优》</value>
<value><![CDATA[
<<Spring实战>>
]]></value>
</util:list>
<bean id="books" class="com.demo.pojo.Books" scope="prototype">
<property name="list" ref="booksList"></property>
</bean>
scope属性值:
singleton 表示单实例对象(默认值)加载Spring配置文件时就会创建单实例对象
prototype 表示多实例对象 调用getBean方法时候创建多实例对象
1.3. bean生命周期以及bean的后置处理器
-
bean的生命周期:
创建-初始化-销毁
-
未配置后置处理器时的bean生命周期
(1)通过构造器创建bean实例 (无参数构造)
(2)为bean的属性设置值和对其他bean的引用 (调用set方法)
(3)调用bean的初始化方法(需要进行配置初始化方法)
(4)使用bean(获取bean实例对象)
(5)当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁方法)
- 添加后置处理器之后的bean生命周期
(1)通过构造器创建bean实例 (无参数构造)
(2)为bean的属性设置值和对其他bean的引用 (调用set方法)
( 将bean实例传递给bean后置处理器的方法 postProcessBeforeInitialization
(3)调用bean的初始化方法(需要进行配置初始化方法)
( 将bean实例传递给bean后置处理器的方法 postProcessAfterInitialization
(4)使用bean(获取bean实例对象)
(5)当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁方法)
* 注: 创建后置处理器后,会为配置文件中的每一个bean实例都配置后置处理器
1.3.1. 举例代码:
后置处理器实现类
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后执行的方法");
return bean;
}
}
#########################################
xml配置
<!-- 配置bean生命周期演示
init-method 配置初始化方法
destroy-method 配置销毁方法
-->
<bean id="orders" class="com.demo.pojo.Orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="篮球"></property>
</bean>
<!-- 配置后置处理器-->
<bean id="myBeanPost" class="com.spring5.bean.MyBeanPost"></bean>
################################################
测试bean
/**
* bean生命周期演示
* (1)通过构造器创建bean实例 (无参数构造)
* (2)为bean的属性设置值和对其他bean的引用 (调用set方法)
* (3)调用bean的初始化方法(需要进行配置初始化方法)
* (4)使用bean(获取bean实例对象)
* (5)当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁方法)
*/
public class Orders {
private String oname;
public Orders() {
System.out.println("第一步:执行无参构造器创建bean实例");
}
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步:调用set方法设置属性值");
}
// 创建执行的初始化方法
public void initMethod(){
System.out.println("第三步:执行初始化方法");
}
// 创建执行的销毁方法
public void destroyMethod(){
System.out.println("第五步:执行销毁方法");
}
}
#######################################
测试代码
/**
* 测试bean的生命周期
*/
public void testBean(){
// ApplicationContext context = new ClassPathXmlApplicationContext("bean7.xml");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean7.xml");
com.spring5.bean.Orders orders = context.getBean("orders", com.spring5.bean.Orders.class);
System.out.println("第四步:获取创建的bean实例对象");
System.out.println(orders);
// 手动销毁bean实例
// ((ClassPathXmlApplicationContext)context).close();
context.close();
}
测试结果:
2. 注解方式
此处主要记录关于注解方式如何指定初始化以及销毁方法
2.1. IOC容器管理Bean生命周期
自定义初始化和销毁方法:
容器在bean进行到当前生命周期的时候来调用自定义的初始化和销毁方法
2.2. 构造对象
- 单实例:在容器启动时创建对象
- 多实例:在每次获取时创建对象
2.3. 初始化
- 对象创建完成并为其赋值后才开始调用初始化方法
2.4. 销毁
- 单例:容器关闭时调用销毁方法
- 多例:容器不调用(不销毁)需要手动调用销毁方法
2.5. 指定初始化和销毁方法
2.5.1 @Bean(initMethod = “init”,destroyMethod = “destory”)
2.5.1 代码测试(单例),(多例测试标记@Scope(“prototype”),需手动调用销毁方法)
配置类
@Configuration
@ComponentScan(value = "com.liuqiang.pojo")
public class MyConfigOfLifeCycle {
// @Scope("prototype")
@Bean(initMethod = "init",destroyMethod = "destory")
public Car getCar(){
return new Car();
}
}
#####################################
测试bean
public class Car {
public Car() {
System.out.println("Car constructor");
}
public void init(){
System.out.println("Car initMethod");
}
public void destory(){
System.out.println("Car destoryMethod");
}
}
#######################################
测试代码
@Test
public void test1(){
// 创建容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfigOfLifeCycle.class);
System.out.println("容器创建完成");
Car bean = applicationContext.getBean(Car.class);
applicationContext.close(); // 销毁容器
// bean.destory(); // 手动调用销毁方法
}
测试结果:
多例测试结果:
2.5.2 . 实现initializingBean接口与DisposableBean接口
initializingBean接口:
当BeanFactory创建好对象并且为所有属性设置好值之后调用afterPropertiesSet方法,完成初始化
DisposableBean接口:
当BeanFactory销毁掉单实例Bean时,调用destory方法完成销毁
2.5.2. 代码测试
接口实现类
@Component
public class Cat implements InitializingBean, DisposableBean {
public Cat(){
System.out.println("Cat constructor...");
}
@Override
public void destroy() throws Exception {
System.out.println("Cat destory...");
}
// 在bean创建好并对其属性赋值之后才被调用
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Cat afterPropertiesSet。。。");
}
}
###############################
测试代码
@Test
public void test2(){ // InitializingBean DisposableBean
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfigOfLifeCycle.class);
System.out.println("容器创建完成");
applicationContext.close();
}
测试结果:
2.5.3. 使用JSR250
注解@PostConstruct
当Bean都装配完成之后执行一些初始化
注解@PreDestory
当Bean在容器中被移除之前给予通知进行销毁
2.5.3. 代码测试
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class Dog {
private ApplicationContext applicationContext;
public Dog() {
System.out.println("Dog constructor");
}
@PostConstruct
public void init(){ // 对象创建并赋值之后调用
System.out.println("Dog @PostConstruct");
}
@PreDestroy
public void destory(){ // 容器移除对象之前
System.out.println("Dog @PreDestroy");
}
}
#####################################
测试代码
@Test
public void test2(){ // JSR250
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfigOfLifeCycle.class);
System.out.println("容器创建完成");
applicationContext.close();
}
测试结果
2.5.4. BeanPostProcessor接口实现 bean的后置处理器:
在bean初始化前后进行一些处理工作,后置处理器需要自己实现BeanPostProcessor接口,重写以下两个方法
postProcessBeforeInitialization
:
Spring在已经创建好Bean实例,在任何初始化方法调用之前,调用后置处理器
postProcessAfterInitialization
:
Spring在已经创建好Bean实例,在任何初始化方法调用之后,调用后置处理器
- 实现流程
BeanPostProcessor.postProcessBeforeInitialization ->
初始化 ->
BeanPostProcessor.postProcessAfterInitialization
- BeanPostProcessor原理流程
populateBean(beanName,mbd,instanceWrapper); // 先给Bean进行属性赋值
initializeBean(){ // 遍历执行进行初始化
applyBeanPostProcessBeforeInitialization(wrappedBean,beanName);
invokeInitMethods(beanName,WrappedBean,mbd); 执行自定义初始化
applyBeanPostProcessAfterInitialization(wrappedBean,beanName);
}
2.5.4. 代码测试
// 后置处理器,在初始化前后进行工作
@Component // 将后置处理器加入到容器中
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
*
* @param bean 容器刚创建好的bean实例
* @param beanName bean实例名字
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization-->"+beanName+"="+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization-->"+beanName+"="+bean);
return bean;
}
}
######################################
测试代码
@Test
public void test2(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfigOfLifeCycle.class);
System.out.println("容器创建完成");
applicationContext.close();
}
测试结果: