Spring中Bean的实例化过程与生命周期
1 实例化过程与生命周期
如下图:
Bean实例(单例bean)生命周期的执行过程如下:
- Spring对bean进行实例化,默认bean是单例;
- Spring对bean进行依赖注入;
- 如果bean实现了BeanNameAware接口,spring将bean的id传给setBeanName()方法;
- 如果bean实现了BeanFactoryAware接口,spring将调用setBeanFactory方法,将BeanFactory实例传进来;
- 如果bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用上下文的引用传入到bean中;
- 如果bean实现了BeanPostProcessor接口,它的postProcessBeforeInitialization方法将被调用;
- 如果bean实现了InitializingBean接口,spring将调用它的afterPropertiesSet接口方法,类似的如果bean使用了init-method属性声明了初始化方法,则再调用该方法;
- 如果bean实现了BeanPostProcessor接口,它的postProcessAfterInitialization接口方法将被调用;
- 此时bean已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁;
- 若bean实现了DisposableBean接口,spring将调用它的distroy()接口方法。如果bean使用了destroy-method属性声明了销毁方法,则再调用该方法;
2 测试BeanPostProcessor接口,InitializingBean接口,DisposableBean接口
我们首先测试一下bean在进行实例化与依赖注入之后,要进行初始化操作的前后一些操作,即测试一下测试BeanPostProcessor接口,InitializingBean接口,DisposableBean接口
测试类如下:
public class Car implements InitializingBean,DisposableBean {
public Car(){
System.out.println("构造器...");
}
//配置文件中的属性init-method指定的方法
public void initMethod(){
System.out.println("属性init-method方法...");
}
//配置文件中的属性destroy-method指定的方法
public void destryMethod(){
System.out.println("属性destroy-method方法...");
}
public void drive(){
System.out.println("开车...");
}
//InitializingBean接口的方法
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean的afterPropertiesSet()方法...");
}
//DisposableBean接口的方法
public void destroy() throws Exception {
System.out.println("DisposableBean接口的destroy()方法...");
}
}
实现BeanPostProcessor接口的类如下:
public class MyPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化前的操作postProcessBeforeInitialization...");
return bean;//返回该bean,因为拿出来处理之后要放回Ioc容器
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化后的操作postProcessAfterInitialization...");
return bean;
}
}
在Xml文件中配置测试类Car和BeanPostProcessor的实现类
<bean id="car" class="Car" init-method="initMethod" destroy-method="destryMethod"/>
<bean class="MyPostProcessor"/>
测试代码:
public class APP {
public static void main(String args[]) {
ClassPathXmlApplicationContext contex=new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = (Car)contex.getBean("car");
car.drive();
contex.close();//关闭应用上下文,则会调用销毁bean的方法
}
}
测试结果:
2 Aware接口:BeanNameAware、BeanFactoryAware、ApplicationContextAware
Aware的含义是感应,Spring容器的IoC中,所有的bean对于spring容器是无意识的,完全可以把spring容器替换成其他的容器而不需要改变你的代码。
如果需要bean对spring有意识,即知道自己在配置中的id是什么,自己是Beanfactory是什么,自己的ApplicationContext是哪个,
则需要用到Aware接口。
xxxAware接口只有一个setXxx()的方法,用于设置Bean的属性
实现这些 Aware接口的Bean在被实例化 之后,可以取得一些相对应的资源,在bean中自动注入对应的属性
例如实现BeanFactoryAware的Bean在实例化后,Spring容器将会注入BeanFactory的实例,而实现ApplicationContextAware的Bean,在Bean被实例化后,将会被注入 ApplicationContext的实例等等。
写一个测试类实现这三个接口:
public class MyBean implements BeanNameAware,BeanFactoryAware,ApplicationContextAware{
private String beanName;
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
//BeanNameAware接口的方法
public void setBeanName(String beanName) {
this.beanName=beanName;
}
//BeanFactoryAware接口的方法
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory=beanFactory;
}
//ApplicationContextAware接口的方法
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}
//用于之后测试打印属性的值
public void print() {
System.out.println("beanName=" + beanName);
System.out.println("beanFactory=" + beanFactory);
System.out.println("applicationContext=" + applicationContext);
}
}
配置:
<bean id="myBean" class="MyBean"/>
测试代码:
public class APP {
public static void main(String args[]) {
ClassPathXmlApplicationContext contex=new ClassPathXmlApplicationContext("applicationContext.xml");
MyBean myBean = (MyBean)contex.getBean("myBean");
myBean.print();
}
}
结果:
beanName=myBean
beanFactory=org.s[email protected]49e4cb85: defining beans [myBean]; root of factory hierarchy
applicationContext=org[email protected]b81eda8: startup date [Thu Jan 31 11:25:58 CST 2019]; root of context hierarchy
从结果可知,容器自动给myban注入了属性,beanName是配置文件中的id,beanFactory是spirng默认的DefaultListableBeanFactory类的一个实例,applicationContext是测试代码中创建的ClassPathXmlApplicationContext的一个实例