Bean的生命周期
要求
- 有spring基础
- 了解过一些设计模式
1.什么是生命周期?
生命周期就是指一个对象的生老病死,在bean中简单的说就是bean的创建到初始化再到bean的销毁的过程(创建->初始化->销毁),然而在spring中正是由spring容器帮我们管理着bean的生命周期,同时也给我们提供了5种方法来控制生命周期,下面依次介绍。
2.自定义Bean初始化、销毁方法
在spring中我们可以自己定义bean的初始化方法及销毁方法,为什么要自己去定义初始化方法、销毁方法?有时候需要在初始化时进行一些业务的处理,在销毁的时候关闭一些资源,这时候就需要我们自定义初始化、销毁方法,这里以注解的形式演示:
package org.example.bean;
/**
* 自定义普通类Computer
* @author JHS
*/
public class Computer {
private String name; //电脑名
Computer(){
System.out.println("创建--(电脑开机)");
}
public void init(){
System.out.println("初始化--(准备环境)");
}
public void destroy(){
System.out.println("销毁--(电脑关机)");
}
}
这里定义了一个自定义的电脑类,包含无参构造、自定义初始化方法、销毁方法,接下来我们将要写一个配置类以注解的形式将Computer类加入到spring容器中。
package org.example.bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 说明:@Configuration相当于我们以前写的xml配置文件,@Bean相当于容器中的bean
* @author JHS
*/
@Configuration
public class ComputerConfig {
//initMethod自定义初始化方法、destroyMethod自定义销毁方法
@Bean(initMethod = "init",destroyMethod = "destroy")
public Computer computer(){
return new Computer();
}
}
启动类:
package org.example.bean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 启动类
* @author JHS
*/
public class Main {
public static void main(String[] args) {
//以注解形式创建应用ComputerConfig.class配置类替换以前的xml
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ComputerConfig.class);
//从容器中获取实例computer既是配置类方法名(bean名字)
context.getBean("computer");
//关闭此应用程序上下文,销毁其bean工厂中的所有bean
context.close();
}
}
结果显示:
我们可以看到控制台打印了我们自动定义的初始化方法与销毁方法,此只是在单例模式下的显示,多例模式下不会调用销毁方法。
3.spring提供的初始化、销毁接口
spring为我们提供了InitializingBean,DisposableBean两个接口,分别代表初始化与销毁,我们只需要实现这两个接口,然后重写它的方法就能达到bean的初始化和销毁,控制台显示效果与上面一样。
package org.example.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
* @author JHS
*/
public class LifeCycle implements InitializingBean, DisposableBean {
//与@PreDestroy注解类似,在容器销毁bean之前通知我们进行清理工作
public void destroy() throws Exception {
System.out.println("销毁");
}
//与@PostConstruct注解类似,在bean创建完成并且属性赋值完成;来执行初始化方法
public void afterPropertiesSet() throws Exception {
System.out.println("初始化");
}
}
4.Bean的后置处理器
spring为我们提供了BeanPostProcessor后置处理器,主要是方便我们在初始化之前和初始化之后进行一些操作,BeanPostProcessor接口提供了两个抽象方法,一个是postProcessBeforeInitialization方法,在初始化之前进行调用,一个是postProcessAfterInitialization方法,在初始化之后进行调用。
package org.example.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* 后置处理器类并通过@Component加入到容器中
* @author JHS
*/
@Component
public class BeanProcessor implements BeanPostProcessor {
/**
* 初始化之前
* @param: [bean 容器中的Bean, beanName bean名字]
* @return: java.lang.Object
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(bean+"--->"+beanName);
return bean;
}
/**
* 初始化之后
* @param: [bean, beanName]
* @return: java.lang.Object
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(bean+"--->"+beanName);
return bean;
}
}
package org.example.bean;
/**
* 自定义普通类Computer
* @author JHS
*/
public class Computer {
private String name; //电脑名
Computer(){
System.out.println("创建--(电脑开机)");
}
public void init(){
System.out.println("初始化--(准备环境)");
}
public void destroy(){
System.out.println("销毁--(电脑关机)");
}
}
配置类:
package org.example.bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 配置类,相当于spring中的xml配置文件
* @author JHS
*/
@ComponentScan("org.example.bean")
@Configuration
public class ComputerConfig {
//initMethod与destroyMethod是上面我们自定义的初始化及销毁方法
@Bean(initMethod = "init",destroyMethod = "destroy")
public Computer computer(){
return new Computer();
}
}
启动类与上面自定义的一样,然后启动:
5.后置处理器原理
为了更加清楚的了解到后置处理器原理,这里我们在BeanPostProcessor接口里面的两个方法分别打上断点,以方便我们调试,然后开启Debug模式。
根据方法栈中的方法依次跟踪到AbstractAutowireCapableBeanFactory抽象类中的doCreateBean()方法。
接下来我们来看doCreateBean()方法里面的内容
接下来我们点击initializaeBean(beanName,exposed,mbd)进入方法内部,在这个方法内部可以看到applyBeanPostProcessorsBeforeInitialization ()与applyBeanPos tProcessorsAfterInitialization()方法,这就是Bean初始化之前与之后调用的方法,而invokeInitMethods()方法则是调用自己实现的初始化方法等。
再点击applyBeanPostProcessorsBeforeInitialization ()方法进入,这里对每个Bean处理器列表进行了遍历,遍历得到容器中所有的BeanPostProcessor,挨个执行beforeInitialization,一但返回null就跳出for循环,不会执行后面的processor.postProcessBeforeInitialization。