時隔一年多,在掌握了Spring、SpringBoot、SpringCloud之後 我再次回頭,重新學習Spring框架 Bean的生命周期學習: 在傳統的XML配置中,可以這樣自定義初始化和銷毀方法: 註解方式的簡單使用: 註意:要有close方法,否則不會列印Car銷毀方法 列印如下: 這裡預設 ...
時隔一年多,在掌握了Spring、SpringBoot、SpringCloud之後
我再次回頭,重新學習Spring框架
Bean的生命周期學習:
在傳統的XML配置中,可以這樣自定義初始化和銷毀方法:
init-method="" destroy-method=""
註解方式的簡單使用:
@Configuration public class LifeCircleConfig { @Bean(initMethod = "init",destroyMethod = "destroy") public Car car(){ return new Car(); } }
public class Car { public Car(){ System.out.println("Construct Car!"); } public void init(){ System.out.println("Car init!"); } public void destroy(){ System.out.println("Car destroy!"); } }
public class LifeCircleTest { private static AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(LifeCircleConfig.class); @Test public void test(){ applicationContext.close(); } }
註意:要有close方法,否則不會列印Car銷毀方法
列印如下:
Construct Car! Car init! Car destroy!
這裡預設的是單實例Bean
如果是多實例的話,按照以上的測試代碼是不會列印的,因為多實例情況下,在獲取Bean的情況下才會創建對象
而且在多例情況下,只會調用初始化和構造方法,不會調用銷毀方法
以上測試代碼只完成了初始化IOC容器,所以什麼都不列印
實現Spring中介面方式:這時候不需要在@Bean中進行配置
public class Car implements InitializingBean, DisposableBean { public Car() { System.out.println("Construct Car!"); } public void afterPropertiesSet() throws Exception { System.out.println("Car init!"); } public void destroy() { System.out.println("Car destroy!"); } }
使用Java原生註解:
public class Car { public Car() { System.out.println("Construct Car!"); } @PostConstruct public void init() { System.out.println("Car init!"); } @PreDestroy public void destroy() { System.out.println("Car destroy!"); } }
使用Spring中Bean的後置處理器:
@Component public class MyBeanPostProcessor implements BeanPostProcessor { /** * 初始化前調用 */ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization " + bean + " " + beanName); return bean; } /** * 初始化後調用 */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization " + bean + " " + beanName); return bean; } }
@Configuration @ComponentScan("org.dreamtech.bean") public class LifeCircleConfig { @Bean public Car car(){ return new Car(); } }
測試後部分列印如下:
Construct Car!
postProcessBeforeInitialization org.dreamtech.bean.Car@2d9d4f9d car
postProcessAfterInitialization org.dreamtech.bean.Car@2d9d4f9d car
BeanPostProcessor原理:
查看這一段源碼:
initializeBean(beanName, exposedObject, mbd)方法中:
Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }
在invokeInitMethods初始化方法之前
調用了applyBeanPostProcessorsBeforeInitialization,也就是調用了所有PostProcessor的Before方法
在invokeInitMethods初始化方法之後
調用了applyBeanPostProcessorsAfterInitialization,也就是調用了所有PostProcessor的After方法
進入applyBeanPostProcessorsBeforeInitialization方法查看源碼:
遍歷所有的Processor,一旦返回null,就會跳出迴圈
@Override public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessBeforeInitialization(result, beanName); if (result == null) { return result; } } return result; }
在initializeBean方法之前,調用的是populateBean方法
作用:給屬性賦值
// Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName, exposedObject, mbd); } }
所以:BeanPostProcessor是在Bean賦值之後,初始化的過程前後執行的
BeanPostProcessor在Spring底層的使用:
獲取IOC容器的介面:
public interface ApplicationContextAware extends Aware { void setApplicationContext(ApplicationContext var1) throws BeansException; }
而它就是基於BeanPostProcessor的,代碼過長就不截取了
class ApplicationContextAwareProcessor implements BeanPostProcessor
或者是參數校驗:也使用到了BeanPostProcessor
public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean
部分代碼如下:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (!this.afterInitialization) { this.doValidate(bean); } return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (this.afterInitialization) { this.doValidate(bean); } return bean; }