圖形介紹
Spring Bean的完整生命週期從創建Spring容器開始,直到最終Spring容器銷燬Bean,生命週期時序圖如下:
生命週期接口分類
Bean的生命週期經歷了多個接口方法的調用,這些接口和方法可分爲以下四類:
1、Bean自身方法
通過的init-method和destroy-method或註解@PostConstruct與@PreDestroy 指定的方法
2、Bean級生命週期接口
包括BeanNameAware、BeanFactoryAware、InitializingBean、DiposableBean
// 獲取bean名稱
public interface BeanNameAware extends Aware {
void setBeanName(String name);
}
// 獲取BeanFactory對象
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
// 對象初始化,與init-method屬性作用相同
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
// 對象銷燬,與destroy-method屬性作用相同
public interface DisposableBean {
void destroy() throws Exception;
}
3、容器級生命週期接口
包括InstantiationAwareBeanPostProcessor 、BeanPostProcessor,注意:InstantiationAwareBeanPostProcessor繼承自BeanPostProcessor,實際中使用InstantiationAwareBeanPostProcessorAdapter提供空實現,從而方便使用
// 對象實例化生命週期接口
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException;
}
// 對象初始化生命週期接口
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
4、BeanFactory後處理器接口
包括BeanFactoryPostProcessor
// 工廠後處理接口,用於修改bean配置(BeanDefinition)
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
生命週期示例演示
@Component
public class Person implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean {
private String name;
@Value("shanghai")
private String address;
@Value("123")
private int phone;
private BeanFactory beanFactory;
private String beanName;
public Person() {
System.out.println("【構造器】調用Person的構造器實例化");
}
public String getName() {
return name;
}
@Autowired
public void setName(@Value("matt") String name) {
System.out.println("【注入屬性】注入屬性name");
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
System.out.println("【注入屬性】注入屬性address");
this.address = address;
}
public int getPhone() {
return phone;
}
public void setPhone(int phone) {
System.out.println("【注入屬性】注入屬性phone");
this.phone = phone;
}
@Override
public String toString() {
return "Person [address=" + address + ", name=" + name + ", phone="
+ phone + "]";
}
// 這是BeanFactoryAware接口方法
@Override
public void setBeanFactory(BeanFactory arg0) throws BeansException {
System.out
.println("【BeanFactoryAware接口】調用BeanFactoryAware.setBeanFactory()");
this.beanFactory = arg0;
}
// 這是BeanNameAware接口方法
@Override
public void setBeanName(String arg0) {
System.out.println("【BeanNameAware接口】調用BeanNameAware.setBeanName()");
this.beanName = arg0;
}
// 這是InitializingBean接口方法
@Override
public void afterPropertiesSet() throws Exception {
System.out
.println("【InitializingBean接口】調用InitializingBean.afterPropertiesSet()");
}
// 這是DiposibleBean接口方法
@Override
public void destroy() throws Exception {
System.out.println("【DiposibleBean接口】調用DiposibleBean.destory()");
}
// 通過<bean>的init-method屬性指定的初始化方法
@PostConstruct
public void myInit() {
System.out.println("【init-method】調用<bean>的init-method屬性指定的初始化方法");
}
// 通過<bean>的destroy-method屬性指定的初始化方法
@PreDestroy
public void myDestory() {
System.out.println("【destroy-method】調用<bean>的destroy-method屬性指定的初始化方法");
}
}
BeanFactoryPostProcessor
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() {
super();
System.out.println("這是BeanFactoryPostProcessor實現類構造器!!");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
throws BeansException {
System.out
.println("BeanFactoryPostProcessor調用postProcessBeanFactory方法");
BeanDefinition bd = arg0.getBeanDefinition("person");
bd.getPropertyValues().addPropertyValue("phone", "110");
}
}
InstantiationAwareBeanPostProcessor
@Component
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
public MyInstantiationAwareBeanPostProcessor() {
super();
System.out.println("這是InstantiationAwareBeanPostProcessorAdapter實現類構造器!!");
}
// 接口方法、實例化Bean之前調用
@Override
public Object postProcessBeforeInstantiation(Class beanClass,
String beanName) throws BeansException {
System.out.println("InstantiationAwareBeanPostProcessor調用postProcessBeforeInstantiation方法");
return null;
}
// 接口方法、實例化Bean之後調用
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("InstantiationAwareBeanPostProcessor調用postProcessAfterInstantiation方法");
return true;
}
// 接口方法、設置某個屬性時調用
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
System.out.println("InstantiationAwareBeanPostProcessor調用postProcessPropertyValues方法");
return pvs;
}
}
BeanPostProcessor
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
super();
System.out.println("這是BeanPostProcessor實現類構造器!!");
}
@Override
public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException {
System.out.println("BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!");
return arg0;
}
@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException {
System.out.println("BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!");
return arg0;
}
}
配置
<context:component-scan base-package="cn.matt.lifecircle"/>
測試
public class BeanLifeTest {
@Test
public void test() {
System.out.println("現在開始初始化容器");
ApplicationContext factory = new ClassPathXmlApplicationContext("spring-context-lifecircle.xml");
System.out.println("容器初始化成功");
//得到Preson,並使用
Person person = factory.getBean("person",Person.class);
System.out.println(person);
System.out.println("現在開始關閉容器!");
((ClassPathXmlApplicationContext)factory).registerShutdownHook();
}
}
運行結果
現在開始初始化容器
這是BeanFactoryPostProcessor實現類構造器!!
BeanFactoryPostProcessor調用postProcessBeanFactory方法
這是BeanPostProcessor實現類構造器!!
這是InstantiationAwareBeanPostProcessorAdapter實現類構造器!!
InstantiationAwareBeanPostProcessor調用postProcessBeforeInstantiation方法
【構造器】調用Person的構造器實例化
InstantiationAwareBeanPostProcessor調用postProcessAfterInstantiation方法
InstantiationAwareBeanPostProcessor調用postProcessPropertyValues方法
【注入屬性】注入屬性name
【注入屬性】注入屬性phone
【BeanNameAware接口】調用BeanNameAware.setBeanName()
【BeanFactoryAware接口】調用BeanFactoryAware.setBeanFactory()
BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!
【init-method】調用<bean>的init-method屬性指定的初始化方法
【InitializingBean接口】調用InitializingBean.afterPropertiesSet()
BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!
InstantiationAwareBeanPostProcessor調用postProcessAfterInitialization方法
容器初始化成功
Person [address=shanghai, name=matt, phone=110]
現在開始關閉容器!
【destroy-method】調用<bean>的destroy-method屬性指定的初始化方法
【DiposibleBean接口】調用DiposibleBean.destory()
一個應用示例
後臺服務以方法調用的形式向外提供服務,在服務啓動時須註冊向外暴露的方法,該註冊功能可利用bean的生命週期的BeanPostProcessor接口,在bean加載完畢後自動註冊,代碼如下:
業務類註解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ExpoService {
String value() default "";
}
業務接口與實現
public interface UserService {
void doSomething();
}
@ExpoService
public class UserServiceImpl implements UserService {
// @Async
@Override
public void doSomething() {
System.out.println("doSomething invoked!");
}
}
請求管理類
@Component
public class RequestManager {
private Map<String, MethodAndInstance> methodMap = new HashMap<String, MethodAndInstance>();
public void addExpoMethod(Method rawMethod, Object rawInstance, Method proxyMethod, Object proxyInstance) {
methodMap.put(rawMethod.getName(), new MethodAndInstance(rawMethod, rawInstance, proxyMethod, proxyInstance));
System.out.println(String.format("****** 添加expo對外暴露方法: %s", rawMethod.getName()));
}
public static class MethodAndInstance {
private Method rawMethod;
private Object rawInstance;
private Method proxyMethod;
private Object proxyInstance;
public MethodAndInstance(Method rawMethod, Object rawInstance, Method proxyMethod, Object proxyInstance) {
this.rawMethod = rawMethod;
this.rawInstance = rawInstance;
this.proxyMethod = proxyMethod;
this.proxyInstance = proxyInstance;
}
public Object getRawInstance() {
return rawInstance;
}
public Object getProxyInstance() {
return proxyInstance;
}
public Method getRawMethod() {
return rawMethod;
}
public Method getProxyMethod() {
return proxyMethod;
}
}
}
使用BeanPostProcessor,註冊接口
@Component
public class ExpoBeanPostProcessor implements BeanPostProcessor {
private Map<String, Object> beanMap = new HashMap<String, Object>();
@Autowired
private RequestManager requestManager;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Class<?> cls = bean.getClass();
if (cls.isAnnotationPresent(ExpoService.class)) {
beanMap.put(beanName, bean);
System.out.println(String.format("======> 業務類原始bean: %s", bean.getClass().getName()));
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object proxyBean, String beanName) throws BeansException {
try {
if (beanMap.containsKey(beanName)) {
System.out.println(String.format("======> 業務類代理bean: %s", proxyBean.getClass().getName()));
Object rawBean = beanMap.remove(beanName);
for (Class<?> cls : rawBean.getClass().getInterfaces()) {
for (Method rowMethod : cls.getDeclaredMethods()) {
Method proxyMethod = proxyBean.getClass().getMethod(rowMethod.getName(), rowMethod.getParameterTypes());
this.requestManager.addExpoMethod(rowMethod, rawBean, proxyMethod, proxyBean);
}
}
}
}
catch (Exception e) { }
return proxyBean;
}
}
配置
<context:component-scan base-package="cn.matt.lifecircle"/>
<task:annotation-driven executor="myExecutor1"/>
<task:executor id="myExecutor1" pool-size="10" />
測試
運行結果
======> 業務類原始bean: cn.matt.lifecircle.UserServiceImpl
======> 業務類代理bean: cn.matt.lifecircle.UserServiceImpl
****** 添加expo對外暴露方法: doSomething
doSomething invoked!
當業務方法添加@Async時,運行結果:
======> 業務類原始bean: cn.matt.lifecircle.UserServiceImpl
======> 業務類代理bean: com.sun.proxy.$Proxy9
****** 添加expo對外暴露方法: doSomething
doSomething invoked!
補充:不存在需要aop功能時,spring bean爲原始類;當存在需要aop功能時,spring bean爲代理類
上述實例存在一個bug:當業務類存在循環引用時,spring會將引用鏈中的某個類提前構造,此時,ExpoBeanPostProcessor在該類的postProcessAfterInitialization方法中獲取的是原始類,而非代理類,由於方法在原始類上調用,導致所有基於aop的功能(如事務,多數據源切換等)失效
解決方法:通過對spring初始化bean的源碼的分析可知(參考Spring 依賴注入時,什麼時候會創建代理類),利用SmartInstantiationAwareBeanPostProcessor接口的getEarlyBeanReference方法獲取到代理類,該方法在BeanPostProcessor接口相關方法之前調用
具體修改如下:
@Component
public class ExpoBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
private Map<String, Object> beanMap = new HashMap<String, Object>();
/**
* @Fields proxyBeanMap : 記錄bean循環引用時的代理bean
*/
private Map<String, Object> proxyBeanMap = new HashMap<String, Object>();
@Autowired
private RequestManager requestManager;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Class<?> cls = bean.getClass();
if (cls.isAnnotationPresent(ExpoService.class)) {
beanMap.put(beanName, bean);
System.out.println(String.format("======> 業務類原始bean: %s", bean.getClass().getName()));
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object proxyBean, String beanName) throws BeansException {
Object originalProxyBean = proxyBean;
try {
if (beanMap.containsKey(beanName)) {
// bean循環引用時, postProcessAfterInitialization獲取不到代理類,須特殊處理
if (proxyBeanMap.containsKey(beanName)) {
proxyBean = proxyBeanMap.get(beanName);
}
System.out.println(String.format("======> 業務類代理bean: %s", proxyBean.getClass().getName()));
Object rawBean = beanMap.remove(beanName);
for (Class<?> cls : rawBean.getClass().getInterfaces()) {
for (Method rowMethod : cls.getDeclaredMethods()) {
Method proxyMethod = proxyBean.getClass().getMethod(rowMethod.getName(), rowMethod.getParameterTypes());
this.requestManager.addExpoMethod(rowMethod, rawBean, proxyMethod, proxyBean);
}
}
}
}
catch (Exception e) { }
return originalProxyBean;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
if (!proxyBeanMap.containsKey(beanName)) {
proxyBeanMap.put(beanName, bean);
}
return bean;
}
}
`