目录
任务描述
本关任务:结合bean
的生命周期修改bean
的name
属性值。
相关知识
为了完成本关任务,你需要掌握 Bean 生命周期的11
个步骤。
Bean 的生命周期
在传统的 Java 应用中,bean
的生命周期非常简单,使用new
关键字对bean
进行实例化,该bean
就可以使用了。当bean
不再被使用后 Java 将自动进行垃圾回收。
相比之下, Spring 容器中bean
的生命周期就比较细致。理解 Spring bean 的生命周期非常重要,因为你或许要利用 Spring 提供的扩展点来自定义bean
的创建过程。
下图展示了 Spring 中 bean
生命周期的11
个步骤:
下面我们对其中部分步骤进行分析:
- 第三步:BeanNameAware
如果bean
实现了 BeanNameAware 接口, Spring 将配置文件中bean
的id
传给setBeanName()
方法。
public class bean implements BeanNameAware{
@Override
public void setBeanName(String beanName) {
System.out.println("第三步:setBeanName方法");
}
}
- 第四步:BeanFactoryAware
如果bean
实现了 ApplicationContextAware 接口,它的setApplicationContext()
方法将被调用,将应用上下文的引用传入到bean
中。
public class bean implements ApplicationContextAware{
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("第四步:setApplicationContext方法");
}
}
- 第六步:InitializingBean
如果bean
实现了 InitializingBean 接口,Spring 将调用它的afterPropertiesSet
方法。
public class bean implements InitializingBean{
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("第六步:afterPropertiesSet方法");
}
}
- 第七、十一步:指定 Bean 的初始化和销毁方法
bean
自定义的初始化和销毁方法如下:
public class bean{
public void init(){
System.out.println("第七步:init方法");
}
public void destory(){
System.out.println("第十一步:destory方法");
}
}
若要自定义的初始化、销毁方法被使用,则需要在 Spring 的配置文件中添加bean
的init-method
和destory-method
属性:
<bean id="bean" class="educoder.bean" init-method="init" destroy-method="destory"></bean>
- 第十步:DisposableBean
如果bean
实现 DisposableBean 接口,则执行destroy
方法。
public class bean implements DisposableBean{
@Override
public void destroy() throws Exception {
System.out.println("第十步:DisposableBean的destory方法");
}
}
注意:执行销毁的时候,必须手动调用close
方法关闭工厂,并且只对scope="singleton"
有效。
后处理器
- 第五、八步:BeanPostProcessor
BeanPostProcessor 称为后处理器。如果存在bean
实现 BeanPostProcessor 接口,则第五步执行postProcessBeforeInitialization
方法、第八步执行postProcessAfterInitialization
方法。
Spring 通过接口反射预先知道,当 Spring 容器创建任何bean
**时,这些后处理器都会发生作用**。
下面例子在任何bean
的初始化之前和之后输出方法名及该bean
的名称。你还可以在初始化bean
的前后实现更复杂的逻辑,因为你有这两个访问内置bean
对象的后置处理程序的方法。
public class afterBean implements BeanPostProcessor {
/**
* 对初始化之前的Bean进行处理
* @param bean 即将初始化的bean
* @param beanname bean的名称
* @return 返回给用户的那个bean,可以修改bean也可以返回一个新的bean
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object obj, String beanName) throws BeansException {
System.out.println("第五步:postProcessBeforeInitialization方法"+beanName);
return obj;
}
/**
* 对初始化之后的Bean进行处理
* @param bean 即将初始化的bean
* @param beanname bean的名称
* @return 返回给用户的那个bean,可以修改bean也可以返回一个新的bean
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object obj, String beanName) throws BeansException {
System.out.println("第八步:postProcessAfterInitialization方法"+beanName);
return obj;
}
}
后处理bean
一般不由bean
本身实现,独立存在,因此需要注册到 Spring 容器中:
<bean class="educoder.afterBean"></bean>
编程要求
在右侧编辑器补充代码,结合bean
的生命周期将bean
的name
属性值修改为Jack
,并在相应周期方法中输出如下信息,实现过程及解释如下图:
测试说明
平台将对你编写的代码进行测试:
预期输出:
参考答案
applicationContext.xml
<?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 id ="dog" class="educoder.Dog"></bean>
<bean id="student" class="step2.Student">
<property name="name" value="Tom"></property>
</bean>
<bean class="step2.MyBeanPostProcessor"></bean>
</beans>
MyBeanPostProcessor.java
package step2;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/********** Begin **********/
public class MyBeanPostProcessor implements BeanPostProcessor{
@Override
public Object postProcessAfterInitialization(Object bean, String beanname) throws BeansException {
Student stu= null;
System.out.println("对初始化之后的Bean进行处理,将Bean的成员变量的值修改了");
if("name".equals(beanname)||bean instanceof Student){
stu=(Student) bean;
stu.setName("Jack");
}
return stu;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanname) throws BeansException {
System.out.println("初始化Bean之前的处理,此时我的名字:"+bean);
return bean;
}
}
/********** End **********/
Student.java
package step2;
import org.springframework.beans.factory.BeanNameAware;
/********** Begin **********/
public class Student implements BeanNameAware{
private String name;
public Student() {}
public void setName(String name) {
System.out.println("设置对象属性setName()");
this.name = name;
}
//实现BeanNameAware接口 并重写setBeanName方法
@Override
public void setBeanName(String beanName){
System.out.println("调用BeanNameAware的setBeanName()方法");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
/********** End **********/
Task.java
package step2;
import educoder.Dog;
import step2.MyBeanPostProcessor;
import step2.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Task {
public Student getBean(){
/********** Begin **********/
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = app.getBean("student",Student.class);
return student;
/********** End **********/
}
}