Spring 之 InitializingBean

Spring 之 InitializingBean

 

 

1、简介

Spring中提供了 InitializingBean 接口,帮助用户实现一些自定义的初始化操作;在bean实例化、属性注入后的提供了一个扩展方法afterPropertiesSet();其实现方式很简单,需要bean实现InitializingBean 接口并且重写 afterPropertiesSet(),且bean要注册到Spring容器中,那么bean在实例化、属性注入后,重写的afterPropertiesSet()就会触发执行;与InitializingBean#afterPropertiesSet()类似效果的是init-method,但是需要注意的是InitializingBean#afterPropertiesSet()执行时机要略早于 init-method;initializingBean#afterPropertiesSet()的调用方式是在bean初始化过程中直接调用bean的afterPropertiesSet();而bean自定义属性init-method是通过java反射的方式进行调用 ;

InitializingBean#afterPropertiesSet() 与 init-method 的执行时机是在BeanPostProcessor#postProcessBeforeInitialization()和BeanPostProcessor#postProcessAfterInitialization()之间;

2、Bean 的生命周期

 

3、源码分析

1、AbstractApplicationContext#refresh是Spring容器启动的关键一步;

2、AbstractApplicationContext#finishBeanFactoryInitialization,是Spring容器启动最后一大步了,前面关于容器必需的组件基本上已经创建好了,这里主要是把需要Spring管理的单例bean实例化注册到Spring容器里;

3、DefaultListableBeanFactory#preInstantiateSingletons,从名字上看更可以看出来是要实例化单例类型的bean了;

4、AbstractBeanFactory#getBean(java.lang.String)-->AbstractBeanFactory#doGetBean

      -->DefaultSingletonBeanRegistry#getSingleton(String,ObjectFactory),

要调用getSingleton(String,ObjectFactory)时,这里要注意一下ObjectFactory是一个函数式接口,使用了java8的lambda表达式的写法,在进入到getSingleton()方法内,执行到ObjectFactory#getObject()方法时,才会触发createBean()方法执行。

5、AbstractAutowireCapableBeanFactory#createBeanString,RootBeanDefinition, Object[])

     -->AbstractAutowireCapableBeanFactory#doCreateBean,这时完成了Bean的实例化,属性还未注入;

6、AbstractAutowireCapableBeanFactory#createBeanString,RootBeanDefinition, Object[])

      -->AbstractAutowireCapableBeanFactory#populateBean,完成属性的注入;
7、顺着AbstractAutowireCapableBeanFactory#populateBean往下执行到initializeBean(),BeanPostProcessor 的postProcessBeforeInitialization()和postProcessAfterInitialization()就是在这个方法中执行的;

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareMethods(beanName, bean);
         return null;
      }, getAccessControlContext());
   }else {
      invokeAwareMethods(beanName, bean);
   }
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
       //执行BeanPostProcessor接口实现类的postProcessBeforeInitialization方法
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
   try {
       //如果bean实现了InitializingBean或者自定义了initMethod,
       //会在这里执行InitializingBean#afterPropertiesSet和initMethod方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
   if (mbd == null || !mbd.isSynthetic()) {
       //执行BeanPostProcessor接口实现类的postProcessAfterInitialization方法
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

 

8、从最外层以剥洋葱的方式一层一层分析到这里,AbstractAutowireCapableBeanFactory#initializeBean()--->invokeInitMethods()才正式走入高潮部分,InitializingBean#afterPropertiesSet和initMethod方法的执行时机就在这里;

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
      throws Throwable {
   //判断bean是否实现了InitializingBean
   boolean isInitializingBean = (bean instanceof InitializingBean);
   if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("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 {
          //如果实现了InitializingBean,真接调用afterPropertiesSet(),简单粗暴;
         ((InitializingBean) bean).afterPropertiesSet();
      }
   }
 
   if (mbd != null && bean.getClass() != NullBean.class) {
       //尝试获取一下bean自定义的init-method方法
      String initMethodName = mbd.getInitMethodName();
      if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
         //如果自定义了init-method方法,在这里开始执行;
         invokeCustomInitMethod(beanName, bean, mbd);
      }
   }
}

9、进入到invokeCustomInitMethod()内,使用java反射来执行自定义的init-method方法;

 

到这里InitializingBean#afterPropertiesSet方法和init-method是什么时候开始调用,是用什么方式来调用的呢,已经分析清楚了,同时还了解到InitializingBean#afterPropertiesSet方法和init-method有类似的效果,执行时机也比较接近,但是是两个完全不同的东西,且InitializingBean#afterPropertiesSet方法的执行时机要稍早于init-method。

4、应用场景
这个扩展点其实是比较有用的一个扩展点,可以用于修改默认设置的属性、添加补充额外的属性值,或者针对关键属性做校验。而Spring内部也有比较经典的实现,有些经常用到,但是可能没有觉察到,如Spring MVC中的RequestMappingHandlerMapping,完成了URL与controller的映射工作。

 

posted @ 2023-12-05 21:08  邓维-java  阅读(800)  评论(0)    收藏  举报