1、概述html
Spring Bean的完整生命週期從建立Spring容器開始,直到最終Spring容器銷燬Bean,生命週期時序圖以下:spring
2、生命週期接口分類ide
Bean的生命週期經歷了多個接口方法的調用,這些接口和方法可分爲如下四類:post
一、Bean自身方法測試
經過<bean>的init-method和destroy-method或註解@PostConstruct與@PreDestroy 指定的方法this
二、Bean級生命週期接口url
包括BeanNameAware、BeanFactoryAware、InitializingBean、DiposableBeanspa
// 獲取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; }
三、容器級生命週期接口.net
包括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; }
四、BeanFactory後處理器接口
包括BeanFactoryPostProcessor
// 工廠後處理接口,用於修改bean配置(BeanDefinition) public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }
3、生命週期示例演示
Bean
@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()
4、一個應用示例
後臺服務以方法調用的形式向外提供服務,在服務啓動時須註冊向外暴露的方法,該註冊功能可利用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" />
測試
@Test public void testMethodRegistry() { ApplicationContext context = new ClassPathXmlApplicationContext("spring-context-lifecircle.xml"); UserService userService = context.getBean(UserService.class); userService.doSomething(); }
運行結果
======> 業務類原始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; } }
參考: