前言:本文分析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,下午。