一文带你深入理解SpringBean生命周期之InitializingBean详解

简介: 一文带你深入理解SpringBean生命周期之InitializingBean详解

概述


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


InitializingBean介绍


执行阶段


首先我们来回顾下Spring Bean整个生命周期。

1671109620298.jpg

执行阶段: 其中标记黄色部分的就是我们本文的主角,它是在bean的属性被设置值之后,调用bean init-method属性指定的方法之前执行的。


作用


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

InitializingBean只有一个方法afterPropertiesSet,见名知意,这个方法是在bean的属性值被设置以后执行。 Spring给我们提供了这么一个扩展点,可以用来做很多的事情, 比如可以修改默认设置的属性,添加补充额外的属性值或者针对关键属性做一个校验。

Spring本身也有很多的Bean实现了InitializingBean接口, 比如Spring MVC中的RequestMappingHandlerMapping就实现了InitializingBean接口,在afterPropertiesSet中完成了一些初始化工作,比如url和controller方法的映射。


实战案例


  1. 定义bean
@Data
@Slf4j
@ToString
@Accessors(chain = true)
public class BeanLifeCycle implements InitializingBean {
    @Value("${prop:hello}")
    private String prop ;
    public BeanLifeCycle() {
        log.info("#################BeanLifeCycle 实例化");
    }
    public void init() {
        log.info("#################BeanLifeCycle 调用init-mthod 初始化");
    }
    public void destroy() {
        log.info("#################BeanLifeCycle 销毁");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("#################BeanLifeCycle 调用afterPropertiesSet方法, 查看属性值prop:[{}],已经被赋值", prop);
        log.info("#################BeanLifeCycle 调用afterPropertiesSet 初始化");
    }
}
@Configuration
public class LifeCycleConfig {
    @Bean(name = "beanLifeCycle", initMethod = "init", destroyMethod = "destroy")
    public BeanLifeCycle createBeanLifeCycle() {
        BeanLifeCycle beanLifeCycle = new BeanLifeCycle();
        return beanLifeCycle;
    }
}
  1. 查看执行结果

image.png

执行结果验证了我们的结论,执行afterPropertiesSet()时bean属性已经被初始化,同时它也是在init-method方法前执行。

代码地址:github.com/alvinlkk/sp…


源码解析


上面我们已经了解了InitializingBean的作用和执行时机,现在我们从源码的角度分析下。

image.png

通过debug我们看到,Bean的创建的入口AbstractAutowireCapableBeanFactorycreateBean方法,createBean最终调用的是doCreateBean方法。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
........
 try {     
            // 为bean设置属性值
      populateBean(beanName, mbd, instanceWrapper);
            // 初始化bean
      exposedObject = initializeBean(beanName, exposedObject, mbd);
    }   
........
}

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

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    ........
    try {
            // 执行初始化方法
      invokeInitMethods(beanName, wrappedBean, mbd);
    }
    ......
    return wrappedBean;
  }

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

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
      throws Throwable {
        // 判断当前bean是否实现了InitializingBean接口
    boolean isInitializingBean = (bean instanceof InitializingBean);
    // 如果当前bean是一个InitializingBean
        if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
      if (logger.isTraceEnabled()) {
        logger.trace("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 {
                // 真正调用当前bean的afterPropertiesSet方法
        ((InitializingBean) bean).afterPropertiesSet();
      }
    }
    if (mbd != null && bean.getClass() != NullBean.class) {
      String initMethodName = mbd.getInitMethodName();
      if (StringUtils.hasLength(initMethodName) &&
          !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
          !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
        // 最后通过反射的方式执行init-method属性对应的方法
                invokeCustomInitMethod(beanName, bean, mbd);
      }
    }
  }

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


总结


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

目录
相关文章
|
Java Spring 容器
一文带你深入理解SpringBean生命周期之Aware详解
一文带你深入理解SpringBean生命周期之Aware详解
2341 2
一文带你深入理解SpringBean生命周期之Aware详解
|
XML Java 数据格式
探索Spring之利剑:ApplicationContext接口
本文深入介绍了Spring框架中的核心接口ApplicationContext,解释了其作为应用容器的功能,包括事件发布、国际化支持等,并通过基于XML和注解的配置示例展示了如何使用ApplicationContext管理Bean实例。
607 6
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
1264 1
|
缓存 监控 安全
Spring AOP 详细深入讲解+代码示例
Spring AOP(Aspect-Oriented Programming)是Spring框架提供的一种面向切面编程的技术。它通过将横切关注点(例如日志记录、事务管理、安全性检查等)从主业务逻辑代码中分离出来,以模块化的方式实现对这些关注点的管理和重用。 在Spring AOP中,切面(Aspect)是一个模块化的关注点,它可以跨越多个对象,例如日志记录、事务管理等。切面通过定义切点(Pointcut)和增强(Advice)来介入目标对象的方法执行过程。 切点是一个表达式,用于匹配目标对象的一组方法,在这些方法执行时切面会被触发。增强则定义了切面在目标对象方法执行前、执行后或抛出异常时所
17615 4
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
1344 2
|
消息中间件 存储 Java
吃透 RocketMQ 消息中间件,看这篇就够了!
本文详细介绍 RocketMQ 的五大要点、核心特性及应用场景,涵盖高并发业务场景下的消息中间件关键知识点。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
吃透 RocketMQ 消息中间件,看这篇就够了!
|
XML Java 程序员
保姆级教程,手把手教你实现SpringBoot自定义starter
保姆级教程,手把手教你实现SpringBoot自定义starter
14162 2
保姆级教程,手把手教你实现SpringBoot自定义starter
|
Java 数据处理 Spring
Spring Boot中的模板引擎选择与配置
Spring Boot中的模板引擎选择与配置
1427 0
|
存储 缓存 负载均衡
图解一致性哈希算法,看这一篇就够了!
近段时间一直在总结分布式系统架构常见的算法。前面我们介绍过布隆过滤器算法。接下来介绍一个非常重要、也非常实用的算法:一致性哈希算法。通过介绍一致性哈希算法的原理并给出了一种实现和实际运用的案例,带大家真正理解一致性哈希算法。
27726 66
图解一致性哈希算法,看这一篇就够了!