Bean的生命周期
生命周期就是对象从创建开始到最终销毁的整个过程 , Spring其实就是一个管理Bean对象的工厂,它负责对象的创建和销毁等
-
Bean生命周期的管理可以参考Spring的源码:
AbstractAutowireCapableBeanFactory
类的doCreateBean()方法
-
研究生命周期的意义:在哪个时间节点上调用了哪个类的哪个方法,把需要在某个特殊的时间点上执行的一段代码放到对应节点上,然后到点会自动被调用
Bean的生命周期之五步
第一步:实例化Bean(调用无参数构造方法)
第二步:给Bean属性赋值(调用set方法)
第三步:初始化Bean(会调用Bean的init方法, 这个init方法需要自己写,并且在配置文件中需要使用init-method
属性指定)
第四步:使用Bean
第五步:销毁Bean(会调用Bean的destroy方法, 这个destroy方法需要自己写,并且在配置文件中需要使用destroy-method
属性指定)
- 只有手动关闭Spring容器, bean的销毁方法才会被调用,需要向下转型执行
ClassPathXmlApplicationContext特有的close方法
定义一个Bean
public class User {
private String name;
public User() {
System.out.println("1.实例化Bean");
}
public void setName(String name) {
this.name = name;
System.out.println("2.Bean属性赋值");
}
//配置bean的初始化方法
public void initBean(){
System.out.println("3.初始化Bean");
}
//配置bean的销毁方法
public void destroyBean(){
System.out.println("5.销毁Bean");
}
}
编写spring的配置文件: init-method
属性指定初始化方法名, destroy-method
属性指定销毁方法名
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--手动指定Bean的初始化方法和销毁方法-->
<bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
<property name="name" value="zhangsan"/>
</bean>
</beans>
测试结果的执行顺序: 1.实例化Bean-->2.Bean属性赋值-->3.初始化Bean-->4.使用Bean-->5.销毁Bean
public class BeanLifecycleTest {
@Test
public void testLifecycle(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
//以下这行代码执行了1.实例化Bean-->2.Bean属性赋值-->3.初始化Bean
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println("4.使用Bean");
// 必须手动关闭Spring容器才会销毁Bean从而执行Bean的销毁方法
ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
context.close();
}
}
Bean生命周期之七步(掌握)
如果你还想在besn的初始化前和初始化后添加代码,需要加入Bean后处理器
(编写一个类实现BeanPostProcessor接口并且实现before和after方法)
- Bean后处理器将作用于整个配置文件中所有的bean
编写日志的Bean后处理器
实现BeanPostProcessor接口并实现postProcessBeforeInitialization和postProcessAfterInitialization
方法
- 这两个方法都有两个参数:第一个参数是刚创建的bean对象, 第二个参数是bean的名字
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean后处理器的before方法执行,即将开始初始化");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean后处理器的after方法执行,已完成初始化");
return bean;
}
}
在spring的配置文件中配置Bean后处理器
(作用于当前配置文件中所有的Bean),并手动指定Bean的初始化方法和销毁方法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--这个Bean后处理器将作用于整个配置文件中所有的bean-->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>
<!--普通bean-->
<bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
<property name="name" value="zhangsan"/>
</bean>
</beans>
测试结果: 1.实例化Bean–>2.Bean属性赋值–>Bean后处理器的before方法–>3.初始化Bean–>Bean后处理器的after方法–>4.使用Bean–>5.销毁Bean
public class BeanLifecycleTest {
@Test
public void testLifecycle(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
// 以下这行代码执行了1.实例化Bean-->2.Bean属性赋值-->Bean后处理器的before方法-->3.初始化Bean-->Bean后处理器的after方法
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println("4.使用Bean");
// 必须手动关闭Spring容器才会销毁Bean从而执行Bean的销毁方法
ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
context.close();
}
}
Bean生命周期之十步(了解)
多添加了三个点位用来检查你这个Bean是否实现了某些特定的接口,如果实现了这些接口则Spring容器会调用这些接口中的方法
- 调用这些接口中的方法目的是为了给你传递一些数据,让你更加方便使用
点位1:在Bean后处理器
的before方法之前(检查Bean是否实现了Aware相关的接口BeanNameAware、BeanClassLoaderAware、BeanFactoryAware)
- 当Bean实现了BeanNameAware,Spring会将Bean的名字传递给Bean
- 当Bean实现了BeanClassLoaderAware,Spring会将加载该Bean的类加载器传递给Bean
- 当Bean实现了BeanFactoryAware,Spring会将Bean工厂对象传递给Bean
点位2:在Bean后处理器
的before方法之后(检查Bean是否实现了InitializingBean接口)
点位3:使用Bean之后或者说销毁Bean之前(检查Bean是否实现了DisposableBean接口)
User类实现了BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean
5个接口并实现它们的所有方法
- InitializingBean接口的afterPropertiesSet方法早于init-method的执行 , DisposableBean接口的destroy方法早于destroy-method的执行
public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
private String name;
public User() {
System.out.println("1.实例化Bean");
}
public void setName(String name) {
this.name = name;
System.out.println("2.Bean属性赋值");
}
public void initBean(){
System.out.println("6.初始化Bean");
}
public void destroyBean(){
System.out.println("10.销毁Bean");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("3.类加载器:" + classLoader);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("3.Bean工厂:" + beanFactory);
}
@Override
public void setBeanName(String name) {
System.out.println("3.bean名字:" + name);
}
@Override
public void destroy() throws Exception {
System.out.println("9.DisposableBean destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("5.afterPropertiesSet执行");
}
}
编写Bean后处理器
重写postProcessBeforeInitialization和postProcessAfterInitialization方法
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("4.Bean后处理器的before方法执行,即将开始初始化");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("7.Bean后处理器的after方法执行,已完成初始化");
return bean;
}
}
在spring的配置文件中配置Bean后处理器
(作用于当前配置文件中所有的Bean),并手动指定Bean的初始化方法和销毁方法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--这个Bean后处理器将作用于整个配置文件中所有的bean-->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>
<!--手动指定Bean的初始化方法和销毁方法-->
<bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
<property name="name" value="zhangsan"/>
</bean>
</beans>
测试结果
public class BeanLifecycleTest {
@Test
public void testLifecycle(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println("8.使用Bean");
// 必须手动关闭Spring容器才会销毁Bean从而执行Bean的销毁方法
ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
context.close();
}
}
Bean的不同管理方式
Spring容器根据Bean的作用域来选择管理方式
对于singleton作用域的Bean
: Spring能够精确地知道该Bean何时被创建,何时初始化完成以及何时被销毁(完整的生命周期)对于prototype作用域的Bean
: Spring只负责Bean的创建, 当客户端程序获取到该Bean后,Spring容器将不再跟踪其生命周期 , 剩下的操作交给客户端管理
将spring配置文件中User类的scope属性设置为prototype
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--将Bean的作用域设置为多实例的-->
<bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean" scope="prototype">
<property name="name" value="zhangsan"/>
</bean>
<!--配置Bean后处理器,这个后处理器将作用于当前配置文件中所有的bean-->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>
</beans>
public class BeanLifecycleTest {
@Test
public void testLifecycle(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println("8.使用Bean");
// 当客户端程序获取到该Bean后,容器将不再跟踪其生命周期即生命周期方法不再执行,剩下的操作交给客户端管理
ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
context.close();
}
}
Spring管理自己new的对象
有些时候可能会需要将我们自己new的java对象交给Spring容器管理,此时需要创建默认的DefaultListableBeanFactory工厂
对象用来注册Bean并指定Bean的id
// 定义Bean
public class User {
}
public class RegisterBeanTest {
@Test
public void testBeanRegister(){
// 自己new的User对象
User user = new User();
// com.powernode.spring6.bean.User@79e2c065
System.out.println(user);
// 创建默认列表BeanFactory对象注册Bean
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 注册Bean
factory.registerSingleton("userBean", user);
// 根据id从spring容器中获取bean
User userBean = factory.getBean("userBean", User.class);
// com.powernode.spring6.bean.User@79e2c065
System.out.println(userBean);
}
}