從接口的名字上不難發現,InitializingBean 的做用就是在 bean 初始化後執行定製化的操做。git
Spring 容器中的 Bean 是有生命週期的,Spring 容許在 Bean 在初始化完成後以及 Bean 銷燬前執行特定的操做,經常使用的設定方式有如下三種:spring
注:如下源碼分析基於spring 5.0.4
springboot
接口定義以下:ide
public interface InitializingBean { void afterPropertiesSet() throws Exception; }
接口只有一個方法afterPropertiesSet
,此方法的調用入口是負責加載 spring bean 的AbstractAutowireCapableBeanFactory
,源碼以下:spring-boot
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } }
從這段源碼能夠得出如下結論:源碼分析
經過 debug 和調用棧找到類InitDestroyAnnotationBeanPostProcessor
, 其中的核心方法,即 @PostConstruct
方法調用的入口:post
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { metadata.invokeInitMethods(bean, beanName); } catch (InvocationTargetException ex) { throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException()); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Failed to invoke init method", ex); } return bean; }
從命名上,咱們就能夠獲得某些信息——這是一個BeanPostProcessor。想到了什麼?在也談Spring容器的生命週期中,提到過BeanPostProcessor的postProcessBeforeInitialization是在Bean生命週期中afterPropertiesSet和init-method以前被調用的。另外經過跟蹤,@PostConstruct
方法的調用方式也是經過發射機制。debug
@PostConstruct
註解的方法 --> afterPropertiesSet
方法 --> init-method
指定的方法。具體能夠參考例子afterPropertiesSet
經過接口實現方式調用(效率上高一點),@PostConstruct
和init-method
都是經過反射機制調用直接執行單測com.skyarthur.springboot.common.bean.InitSequenceBeanTest
, 請戳代碼下載地址code
核心代碼以下:blog
@Slf4j public class InitSequenceBean implements InitializingBean { public InitSequenceBean() { log.info("InitSequenceBean: construct"); } @Override public void afterPropertiesSet() throws Exception { log.info("InitSequenceBean: afterPropertiesSet"); } @PostConstruct public void postConstruct() { log.info("InitSequenceBean: postConstruct"); } public void initMethod() { log.info("InitSequenceBean: initMethod"); } } @Configuration public class SystemConfig { @Bean(initMethod = "initMethod", name = "initSequenceBean") public InitSequenceBean initSequenceBean() { return new InitSequenceBean(); } } @Slf4j public class InitSequenceBeanTest extends ApplicationTests { @Autowired private InitSequenceBean initSequenceBean; @Test public void initSequenceBeanTest() { log.info("Finish: {}", initSequenceBean.toString()); } }