bean的生命周期是面试题中出现频率很高的一题,以前总是靠死记硬背来记住(毕竟在对bean的使用中这些操作很少),现在才尝试着用代码一试。
直接上代码:
xml配置bean:
<bean id="person" class="bean.Person" init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="hsw"/>
<property name="age" value="12"/>
</bean>
这里只配置了属性的值和init-method以及destroy-method两个方法。
bean的类代码:
@ToString
public class Person implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, DisposableBean, InitializingBean {
private String name;
private int age;
public Person() {
System.out.println("无参构造函数!");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("setter begin!");
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
System.out.println("setter begin!");
this.age = age;
}
public String getBeanName() {
return beanName;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
private String beanName;
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
@Override
public void setBeanName(String s) {
System.out.println("beanNameAware");
this.beanName = s;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("beanFactoryAware");
this.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("applicationContextAware");
this.applicationContext = applicationContext;
}
private void initMethod() {
System.out.println("init-method");
}
private void destroyMethod() {
System.out.println("destroy-method");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean afterPropertiesSet");
}
@Override
public void destroy() throws Exception {
System.out.println("Disposable destroy");
}
}
可以看到bean实现的方法有很多,首先是xxxAware三个接口,能让bean察觉到spring容器存在的三个接口。然后就是两个非方法对应xml配置中的两个配置:initMethod、destroyMethod。最后就是实现了InitializingBean 的 afterPropertiesSet 方法和 Disposable 的 destroy 方法。这些方法都会在bean的生命周期中被调用以实现一些自定义的功能。
PostProcessor即bean的后处理器
自定义InstantiationAwareBeanPostProcessor:
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("postProcessBeforeInstantiation");
return null;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
System.out.println("postProcessProperties");
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInstantiation");
return true;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization");
return bean;
}
}
在xml文件中配置一下:
<bean id="myInstantiationAwareBeanPostProcessor" class="others.MyInstantiationAwareBeanPostProcessor"/>
这里有必要说一下:此自定义类命名为MyInstantiationBeanPostProcessor,实现了InstantiationAwareBeanPostProcessor 的几个方法。意思是对实例化阶段处理。但却多出了与接口不太相符的初始化方法,这是因为InstantiationAwareBeanPostProcessor的父接口是BeanPostProcessor,这个接口有两个默认自定义类的接口没有实现(postProcessBeforeInitialization 和 postProcessAfterInitialization),我直接在自定义类中实现了(当然也可以自己自定义一个如MyInitialazation...自定义类实现)。
测试方法:
@Test
public void testOne() {
ClassPathXmlApplicationContext context
= new ClassPathXmlApplicationContext("/bean.xml");
Person person = (Person) context.getBean("person");
System.out.println(person);
context.close();
}
启动容器获取bean打印后关闭容器。
运行结果:
postProcessBeforeInstantiation
无参构造函数!
postProcessAfterInstantiation
postProcessProperties
setter begin!
setter begin!
beanNameAware
beanFactoryAware
applicationContextAware
postProcessBeforeInitialization
InitializingBean afterPropertiesSet
init-method
postProcessAfterInitialization
Person(...)//person信息,这里略
Disposable destroy
destroy-method
流程梳理
所以根据输出结果可以得出bean的生命周期大致为:
- InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation,顾名思义实例化之前调用,方法有两个参数,bean所属class对象和beanName,返回Object对象。
- 实例化,配置时使用的是set注入属性,所以这里调用无参构造方法。如果使用的是有参构造方法就不会了。
- InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation,顾名思义实例化之后调用,方法依旧两个参数:Object bean, String beanName,返回boolean。
这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。如果该方法返回false,会忽略属性值的设置;如果返回true,会按照正常流程设置属性值
- InstantiationAwareBeanPostProcessor 的 postProcessProperties 。
方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation方法返回false,该方法不会被调用。可以在该方法内对属性值进行修改
- 开始调用bean的setter方法注入配置的属性值。
- 注入配置好的aware接口的属性。
- BeanPostProcessor 的 postProcessBeforeInitialization方法,即调用初始化方法前进行相关处理,方法参数同样为Object bean, String beanName,返回Object对象。这里可以返回已经初始化好了bean,也可以返回包装后的bean,甚至其他bean。
- bean实现的接口InitializingBean 的 afterPropertiesSet方法,无参数无返回值,但在bean内部可以访问bean的相关属性。
- 然后就是init-method方法了,无参数无返回值,在bean内部。
- BeanPostProcessor 的 PostProcessAfterInitialation方法,参数返回值和before相同。
- 至此相关作用域获取到bean,这里是打印了bean的信息。如果是原型模式,bean的生命周期随其作用域。如果配置的是单例,则由spring容器管理,后面容器关闭时会有后续过程。
- 调用DisposableBean 的 destroy 方法, 无参数无返回值。
- 调用xml文件配置的destroy-method。
网友评论