前言:本文分析InitializingBean和init-method方法,其實該知識點在AbstractAutowireCapableBeanFactory#initializeBean方法中有所說起,這裏對其進行詳細分析。安全
InitializingBean是一個接口,它只包含一個afterPropertiesSet方法:ide
1 public interface InitializingBean { 2 3 /** 4 * 該方法在BeanFactory設置完了全部的屬性以後被調用<br/> 5 * 該方法容許bean實例設置了全部bean屬性時執行初始化工做,若是該過程出現了錯誤,則須要拋出異常<br/> 6 * Invoked by the containing {@code BeanFactory} after it has set all bean properties 7 * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc. 8 * <p>This method allows the bean instance to perform validation of its overall 9 * configuration and final initialization when all bean properties have been set. 10 * 11 * @throws Exception in the event of misconfiguration (such as failure to set an 12 * essential property) or if initialization fails for any other reason 13 */ 14 void afterPropertiesSet() throws Exception; 15 16 }
分析:測試
Spring在完成實例化後,設置完全部屬性,進行"Aware"接口和"BeanPostProcessor"前置處理後,會接着檢測當前bean對象是否實現了InitializingBean接口,若是是,則會調用其afterPropertiesSet方法進一步調整bean實例對象的狀態。this
1 public class UserDefinedInitializingBean implements InitializingBean { 2 3 private String msg; 4 5 public String getMsg() { 6 return msg; 7 } 8 9 public void setMsg(String msg) { 10 this.msg = msg; 11 } 12 13 @Override 14 public void afterPropertiesSet() throws Exception { 15 System.out.println("InitializingBean afterPropertiesSet......"); 16 this.msg = "修改了msg,msg=hello initializingBean!!!!!!"; 17 } 18 }
進行以下配置:spa
1 <bean id="userDefinedInitializingBean" class="com.dev.basebean.initializingbean.UserDefinedInitializingBean" 2 p:msg="i am msg!!!"/>
測試:debug
1 @Test 2 public void initializingBeanTest() { 3 ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:com/dev/config/initializingbean/initializingbean.xml"); 4 UserDefinedInitializingBean initializingBean = context.getBean(UserDefinedInitializingBean.class); 5 System.out.println(initializingBean.getMsg()); 6 }
運行結果以下:3d
從運行結果來看,msg屬性被咱們修改了,在afterPropertiesSet方法中,這至關於Spring又提供給咱們一種能夠改變bean實例對象的方法。code
InitializingBean的afterPropertiesSet方法就是在invokeInitMethods方法中被執行的。orm
AbstractAutowireCapableBeanFactory#invokeInitMethods:xml
1 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) 2 throws Throwable { 3 4 // 首先先檢查是不是InitializingBean,若是是,則須要調用afterPropertiesSet() 5 boolean isInitializingBean = (bean instanceof InitializingBean); 6 if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { 7 if (logger.isDebugEnabled()) { 8 logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); 9 } 10 // 安全模式 11 if (System.getSecurityManager() != null) { 12 try { 13 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { 14 ((InitializingBean) bean).afterPropertiesSet(); 15 return null; 16 }, getAccessControlContext()); 17 } catch (PrivilegedActionException pae) { 18 throw pae.getException(); 19 } 20 } else { 21 // 屬性初始化處理 22 ((InitializingBean) bean).afterPropertiesSet(); 23 } 24 } 25 26 if (mbd != null && bean.getClass() != NullBean.class) { 27 String initMethodName = mbd.getInitMethodName(); 28 if (StringUtils.hasLength(initMethodName) && 29 !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && 30 !mbd.isExternallyManagedInitMethod(initMethodName)) { 31 // 激活用戶自定義的初始化方法 32 invokeCustomInitMethod(beanName, bean, mbd); 33 } 34 } 35 }
分析:
對init-method進行示例,只需根據上面示例進行一點調整便可。
1 <bean id="userDefinedInitializingBean" class="com.dev.basebean.initializingbean.UserDefinedInitializingBean" 2 p:msg="i am msg!!!" init-method="initMethod"/>
在UserDefinedInitializingBean中增長以下代碼:
1 public void initMethod() { 2 System.out.println("經過init-method方法對msg屬性進行修改"); 3 this.msg = "修改了msg,msg=hello init-method!!!!!!"; 4 }
運行結果以下:
從結果上能夠看到init-method方法是在afterPropertiesSet方法以後,而且達到了一樣的效果,對代碼無侵入性。
分析到這裏其實已經把bean的生命週期都總結出來,下篇文章進行具體總結,這裏想來看本篇小結。
從invokeInitMethods方法中,咱們知道init-method指定的方法會在afterPropertiesSet方法後執行,若是afterPropertiesSet方法執行過程當中出現異常,init-method方法是不會執行的。使用init-method使其對業務代碼的侵入下降,雖然init-method是基於xml配置文件的,但咱們也能夠經過@PostConstruct註解的形式來進行替換。
至此InitializingBean和init-method已分析完畢,對於DisposableBean和destroy-method與init類似,這裏再也不進行贅述。
by Shawn Chen,2019.05.05,下午。