目录
任务描述
在传统的Java
应用中,Bean
的生命周期非常简单,使用new
关键字对Bean
进行实例化,该Bean
就可以使用了,当Bean
不再被使用后Java
将自动进行垃圾回收。
相比之下,Spring
容器中bean
的生命周期就比较细致。理解 Spring bean
的生命周期非常重要,因为你或许要利用Spring
提供的扩展点来自定义Bean
的创建过程。
本关任务:结合Bean
的生命周期修改Bean
的name
属性值。
相关知识
为了完成本关任务,你需要掌握 如下知识:
Bean
生命周期的11
个步骤。
Bean 的生命周期
下图展示了Spring
中Bean
生命周期的11
个步骤:
图 1 Bean 的生命周期图
下面我们对其中部分步骤进行分析:
- 第三步:
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>
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End
区域内进行代码补充,结合Bean
的生命周期将User
类Bean
实例的name
属性值修改为Jack
,并把周期过程输出如下(图中的黑色字体为过程,红色字体为说明):
图 2 周期过程图
右侧代码文件共中有配置文件、MyBeanPostProcessor
类、Task
类、User
类需要根据提示补充,后台会自动创建Task
对象调用getBean()
方法获取Bean
输出周期过程。
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。
预期输出:
设置对象属性setUsername()
调用BeanNameAware的setBeanName()方法
初始化Bean之前的处理,此时我的名字:User{username='Tom'}
对初始化之后的Bean进行处理,将Bean的成员变量的值修改了
设置对象属性setUsername()
User{username='Jake'}
参考代码
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="user" class="com.educoder.step2.User">
<property name="username" value="Tom"></property>
</bean>
<!-- 配置后处理器 -->
<bean class="com.educoder.step2.MyBeanPostProcessor"></bean>
</beans>
MyBeanPostProcessor.java
package com.educoder.step2;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
//对初始化之后的Bean进行处理
@Override
public Object postProcessAfterInitialization(Object bean, String beanname) throws BeansException {
/********** Begin **********/
System.out.println("对初始化之后的Bean进行处理,将Bean的成员变量的值修改了");
User stu = null;
if("user".equals(beanname) || bean instanceof User) {
stu = (User) bean;
stu.setUsername("Jake");
return stu;
}
return bean;
/********** End **********/
}
//对初始化之前的Bean进行处理
@Override
public Object postProcessBeforeInitialization(Object bean, String beanname) throws BeansException {
/********** Begin **********/
System.out.println("初始化Bean之前的处理,此时我的名字:"+bean);
return bean;
/********** End **********/
}
}
User.java
package com.educoder.step2;
import org.springframework.beans.factory.BeanNameAware;
public class User implements BeanNameAware {
private String username;
public User() {}
//注入username属性
public void setUsername(String username) {
/********** Begin **********/
System.out.println("设置对象属性setUsername()");
this.username = username;
/********** End **********/
}
//实现BeanNameAware接口 并重写setBeanName方法
@Override
public void setBeanName(String name) {
/********** Begin **********/
System.out.println("调用BeanNameAware的setBeanName()方法" );
/********** End **********/
}
//返回字符串:User{name='属性值'}
@Override
public String toString() {
/********** Begin **********/
return "User{" +
"username='" + username + '\'' +
'}';
/********** End **********/
}
}
Task.java
package com.educoder.step2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Task {
//获取User类Bean实例
public User getBean(){
/********** Begin **********/
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
User bean = (User) app.getBean("user");
return bean;
/********** End **********/
}
}