概述

Spring Bean的生命周期是一个比较复杂的过程,从创建到销毁,包含了一些列的过程,本章重点讲解下Spring Bean的afterPropertiesSet()

InitializingBean介绍

执行阶段�

首先我们来回顾下Spring Bean整个生命周期。
SpringBean生命周期——InitializingBean详解 - 图1
执行阶段:其中标记黄色部分的就是我们本文的主角,它是在bean的属性被设置值之后,调用bean init-method属性指定的方法之前执行的。

作用

  1. public interface InitializingBean {
  2. /**
  3. * Invoked by the containing {@code BeanFactory} after it has set all bean properties
  4. * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
  5. * <p>This method allows the bean instance to perform validation of its overall
  6. * configuration and final initialization when all bean properties have been set.
  7. * @throws Exception in the event of misconfiguration (such as failure to set an
  8. * essential property) or if initialization fails for any other reason
  9. */
  10. void afterPropertiesSet() throws Exception;
  11. }

InitializingBean只有一个方法afterPropertiesSet,见名知意,这个方法是在bean的属性值被设置以后执行。 Spring给我们提供了这么一个扩展点,可以用来做很多的事情, 比如可以修改默认设置的属性,添加补充额外的属性值或者针对关键属性做一个校验。
Spring本身也有很多的Bean实现了InitializingBean接口, 比如Spring MVC中的RequestMappingHandlerMapping就实现了InitializingBean接口,在afterPropertiesSet中完成了一些初始化工作,比如url和controller方法的映射。

实战案例

  1. 定义bean ```java @Data @Slf4j @ToString @Accessors(chain = true) public class BeanLifeCycle implements InitializingBean {

    @Value(“${prop:hello}”) private String prop ;

    public BeanLifeCycle() {

    1. log.info("#################BeanLifeCycle 实例化");

    }

    public void init() {

    1. log.info("#################BeanLifeCycle 调用init-mthod 初始化");

    }

    public void destroy() {

    1. log.info("#################BeanLifeCycle 销毁");

    }

    @Override public void afterPropertiesSet() throws Exception {

    1. log.info("#################BeanLifeCycle 调用afterPropertiesSet方法, 查看属性值prop:[{}],已经被赋值", prop);
    2. log.info("#################BeanLifeCycle 调用afterPropertiesSet 初始化");

    } }

@Configuration public class LifeCycleConfig {

  1. @Bean(name = "beanLifeCycle", initMethod = "init", destroyMethod = "destroy")
  2. public BeanLifeCycle createBeanLifeCycle() {
  3. BeanLifeCycle beanLifeCycle = new BeanLifeCycle();
  4. return beanLifeCycle;
  5. }

}

  1. 2. 查看执行结果
  2. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/384158/1655526335701-2e4cb404-759f-44bb-ae81-6bca4cb0fde5.png#clientId=u150bf580-51b1-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=228&id=u8e7b4563&margin=%5Bobject%20Object%5D&name=image.png&originHeight=456&originWidth=2708&originalType=binary&ratio=1&rotation=0&showTitle=false&size=142759&status=done&style=none&taskId=u87c3903a-fa8e-4bce-9048-fc0cd552aea&title=&width=1354)<br />执行结果验证了我们的结论,执行`afterPropertiesSet()`时bean属性已经被初始化,同时它也是在init-method方法前执行。<br />代码地址:[https://github.com/alvinlkk/springboot-demo/tree/master/springboot-bean-lifecycle](https://github.com/alvinlkk/springboot-demo/tree/master/springboot-bean-lifecycle)
  3. <a name="aoi6J"></a>
  4. # 源码解析
  5. 上面我们已经了解了`InitializingBean`的作用和执行时机,现在我们从源码的角度分析下。<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/384158/1655527151155-6c1ff0be-4fd8-4de2-b592-36f240416b37.png#clientId=u150bf580-51b1-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=292&id=u03cf1186&margin=%5Bobject%20Object%5D&name=image.png&originHeight=584&originWidth=1684&originalType=binary&ratio=1&rotation=0&showTitle=false&size=233695&status=done&style=none&taskId=u3b2607e6-29da-493d-8d3f-a257da971a9&title=&width=842)<br />通过debug我们看到,Bean的创建的入口`AbstractAutowireCapableBeanFactory`的`createBean`方法,`createBean`最终调用的是`doCreateBean`方法。
  6. ```java
  7. protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  8. throws BeanCreationException {
  9. ........
  10. try {
  11. // 为bean设置属性值
  12. populateBean(beanName, mbd, instanceWrapper);
  13. // 初始化bean
  14. exposedObject = initializeBean(beanName, exposedObject, mbd);
  15. }
  16. ........
  17. }

doCreateBean方法中相关的就是populateBean方法和initializeBean方法,populateBean方法主要为bean设置属性值,我们重点关注初始化Bean方法initializeBean

  1. protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
  2. ........
  3. try {
  4. // 执行初始化方法
  5. invokeInitMethods(beanName, wrappedBean, mbd);
  6. }
  7. ......
  8. return wrappedBean;
  9. }

initializeBean中关键的是执行invokeInitMethods方法,在这里面调用afterPropertiesSet方法。

  1. protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
  2. throws Throwable {
  3. // 判断当前bean是否实现了InitializingBean接口
  4. boolean isInitializingBean = (bean instanceof InitializingBean);
  5. // 如果当前bean是一个InitializingBean
  6. if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
  7. if (logger.isTraceEnabled()) {
  8. logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
  9. }
  10. if (System.getSecurityManager() != null) {
  11. try {
  12. AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
  13. ((InitializingBean) bean).afterPropertiesSet();
  14. return null;
  15. }, getAccessControlContext());
  16. }
  17. catch (PrivilegedActionException pae) {
  18. throw pae.getException();
  19. }
  20. }
  21. else {
  22. // 真正调用当前bean的afterPropertiesSet方法
  23. ((InitializingBean) bean).afterPropertiesSet();
  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.hasAnyExternallyManagedInitMethod(initMethodName)) {
  31. // 最后通过反射的方式执行init-method属性对应的方法
  32. invokeCustomInitMethod(beanName, bean, mbd);
  33. }
  34. }
  35. }

以上就是从源码层面理解InitializingBean的调用时机。

总结

InitializingBean是Spring中很关键的一个扩展接口,其实它和bean中init-method属性对应的方法功能是一致的,都是初始化bean,我们可以二选一实现即可,当然同时使用也没有问题。init-method是通过反射实现的,性能相对差一点点。另外,如果调用afterPropertiesSet方法时出错,则不会调用init-method指定的方法。

参考

http://www.cnblogs.com/zrtqsk/p/3735273.htm
https://juejin.cn/post/6964604073223913509