statelesswidget 初始化执行方法_Spring的初始化回调你真的搞懂了吗?
发布日期:2021-06-24 11:23:38 浏览次数:2 分类:技术文章

本文共 22731 字,大约阅读时间需要 75 分钟。

3bb6e7008cb99c677a631d635053be90.png

Spring框架提供了多种方式控制bean初始化的过程,开发者可以自定义初始化的逻辑。对于这么多的初始化方式,你是否有深入了解过?

有如下几种自定义bean初始化逻辑的方式:

  1. 使用@PostConstruct注解
  2. 自定义初始化方法,比如@Bean(initMethod = "method1")
  3. 实现InitializingBean接口的afterPropertiesSet()方法
  4. 实现SmartInitializingSingleton接口的afterSingletonsInstantiated()方法

这四种方式都可以用于自定义bean的初始化。但是每种方法执行的时机不太一样,最大的不同是前面三种只针对某个bean生效,最后一种是针对所有bean生效。下面通过Spring源码来给大家逐一介绍。

首先自定义一个bean,分别实现上述4种方式。

package com.ubuntuvim.spring.createbean;import org.springframework.beans.factory.InitializingBean;import org.springframework.beans.factory.SmartInitializingSingleton;import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;import org.springframework.beans.factory.support.RootBeanDefinition;import javax.annotation.PostConstruct;/** * 验证不同方式初始化回调的执行顺序: * 0. 执行初始化回调BeanPostProcessor.postProcessBeforeInitialization()方法 * 1. 执行初始化回调@PostConstruct注解定义的方法 * 2. 执行初始化回调InitializingBean.afterPropertiesSet()方法 * 3. 执行初始化回调@Bean(initMethod = "beanInit")定义的方法 * 4. 执行初始化回调BeanPostProcessor.postProcessAfterInitialization()方法 * 5. 执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法, *         此回调是在bean实例化和初始化完成之后执行的 * * @Author: ubuntuvim * @Date: 2020/10/18 上午1:16 */public class InitCallbackBean implements InitializingBean, SmartInitializingSingleton {    /**     * 如果一个类中多个方法都使用@PostConstruct注解声明,则会根据方法名按照字母升序顺序执行。     * 比如init()和afterPropertiesSet()都加了注解,那么先执行afterPropertiesSet()方法     */    @PostConstruct    public void init() {        System.out.println("执行初始化回调@PostConstruct注解定义的方法");    }    @PostConstruct    public void init2() {        System.out.println("执行初始化回调@PostConstruct注解定义的方法init2()");    }    /**     * 如果用户在afterPropertiesSet()方法上也使用了@PostConstruct注解,此方法在后置处理器中会先被执行     * @see InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)     * 然后在执行初始化回调接口InitializingBean时不会再次执行。     * @see AbstractAutowireCapableBeanFactory#invokeInitMethods(String, Object, RootBeanDefinition)     * 也就是说同时在回调接口InitializingBean上同时使用@PostConstruct注解只会执行一次,但是可以改变方法的执行时机,     * 比如本类中init()和afterPropertiesSet()都加了@PostConstruct注解,那么先执行afterPropertiesSet()方法,     * 如果afterPropertiesSet()方法不加@PostConstruct注解,那么会先执行init()方法,再执行afterProperties()方法。     * 因为@PostConstruct注解优先于回调接口InitializingBean执行     *     * 如果@Bean注解中自定义的方法也使用@PostConstruct注解声明,那么这个方法会重复执行。     * 1. 后置处理器处理@PostConstruct注解方法的时候执行一次,     * 2. 执行自定义的方法的时候也执行一次     *     * @Bean(initMethod = "afterPropertiesSet")     * 如果自定义的方法和InitializingBean的回调方法一致。     * afterPropertiesSet()方法会执行一次,只执行InitializingBean的回调,不会在执行自定义方法的回调。     * 原因可以看Spring源码,位置:     * @see AbstractAutowireCapableBeanFactory#invokeInitMethods(String, Object, RootBeanDefinition)     *     * @Bean(initMethod = "initBean")     * 如果自定义的方法也使用了@PostConstruct声明,那么initBean()会执行两次。     * 1. 后置处理器处理@PostConstruct注解方法的时候执行一次,     * 2. 执行自定义的方法的时候也执行一次     *     * 总结一句话,InitializingBean.afterPropertiesSet()方法只会执行一次。     *             @PostConstruct 声明的方法都会执行,不管有几个,执行顺序按照方法名升序执行     *///    @PostConstruct    @Override    public void afterPropertiesSet() throws Exception {        System.out.println("执行初始化回调InitializingBean.afterPropertiesSet()方法");    }    @Override    public void afterSingletonsInstantiated() {        System.out.println("执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法");    }    @PostConstruct    private void beanInit() {        System.out.println("执行初始化回调@Bean(initMethod = "beanInit")定义的方法");    }}

通过@Bean方式把此类注入到Spring容器中。

@ComponentScan@Configurationpublic class Config {    @Bean(initMethod = "beanInit")    public InitCallbackBean initCallbackBean() {        return new InitCallbackBean();    }}

首先运行看结果是怎么样的。

执行初始化回调@PostConstruct注解定义的init方法执行初始化回调@Bean(initMethod = "beanInit")定义的方法,并且此方法也使用了@PostConstruct注解执行初始化回调@PostConstruct注解定义的方法init2()执行初始化回调InitializingBean.afterPropertiesSet()方法执行初始化回调@Bean(initMethod = "beanInit")定义的方法,并且此方法也使用了@PostConstruct注解执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法

通过运行结果分析,可以看到使用@PostConstruct注解的方法会第一个执行,beanInit方法同时使用了@PostConstruct注解,并且同时在@Bean中也指定成bean自定义的初始化方法,所以这个方法执行了两次。如果同一个类中有个多个方法都使用了@PostConstruct注解,那么这些被注解的方法都会被执行,但是执行的顺序不一定是方法在类中的代码顺序。

做点好玩的事情,在afterPropertiesSet()方法上也使用@PostConstruct注解,再运行看看结果是怎么样,会不会执行两遍?

执行初始化回调@PostConstruct注解定义的init方法执行初始化回调InitializingBean.afterPropertiesSet()方法执行初始化回调@Bean(initMethod = "beanInit")定义的方法,并且此方法也使用了@PostConstruct注解执行初始化回调@PostConstruct注解定义的方法init2()执行初始化回调@Bean(initMethod = "beanInit")定义的方法,并且此方法也使用了@PostConstruct注解执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法

这个就比较有意思了,可以看到afterPropertiesSet()方法只执行了一遍。

这几种初始化方法执行顺序是怎么设定的呢?为何使用@PostConstruct注解的方法可以执行多次,而afterPropertiesSet()方法却执行一次呢?

带这些疑问,我们阅读Spring源码,从源码中找答案。

不同初始化方式的执行时机

这些初始化方法都是在有bean实例之后执行的,我们可以大概的猜测到这些初始化回调应该是在Spring框架完成bean实例化,进行属性填充的时候执行的。

如果你对Spring框架bean的实例化、初始化不是很了解的请看之前的系列博客:https://www.toutiao.com/i6887194772914733571

直接打开如下类方法,

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

这个方法是Spring容器非常核心的方法,它处理了很多事情:单例实例化、填充属性、执行初始化回调、注册销毁回调方法。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)  throws BeanCreationException {  // Instantiate the bean.  BeanWrapper instanceWrapper = null;  if (mbd.isSingleton()) {    // 从缓存中查询,如果是bean定义是一个bean工厂实例可以直接拿到。    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);  }  if (instanceWrapper == null) {    // 普通bean,根据bean定义创建bean实例,并包装成BeanWrapper返回    instanceWrapper = createBeanInstance(beanName, mbd, args);  }  // 获取经过jdk1.8的Optional类包装过的非空对象  final Object bean = instanceWrapper.getWrappedInstance();  // 获取bean的class类型  Class> beanType = instanceWrapper.getWrappedClass();  if (beanType != NullBean.class) {    mbd.resolvedTargetType = beanType;  }  // Allow post-processors to modify the merged bean definition.  synchronized (mbd.postProcessingLock) {    if (!mbd.postProcessed) {      try {        // 执行后置处理器接口MergedBeanDefinitionPostProcessor,bean实例化之后,就可以通过反射获取到类或者属性上的注释信息        // 处理@Resource、@Autowired、@Value注解的定义信息,并把这些注解的定义信息放在缓存中。待后续属性填充的时候使用。        // 如果有则吧注解信息转换成AutowiredFieldElement对象或者AutowiredMethodElement对象或者ResourceElement对象        // 实现类有:AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor等        applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);      }      catch (Throwable ex) {        throw new BeanCreationException(mbd.getResourceDescription(), beanName,                                        "Post-processing of merged bean definition failed", ex);      }      mbd.postProcessed = true;    }  }  // Eagerly cache singletons to be able to resolve circular references  // even when triggered by lifecycle interfaces like BeanFactoryAware.  // 单例bean && 允许循环依赖 && bean正在被创建  boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&                                    isSingletonCurrentlyInCreation(beanName));  if (earlySingletonExposure) {    if (logger.isTraceEnabled()) {      logger.trace("Eagerly caching bean '" + beanName +                   "' to allow for resolving potential circular references");    }    /**             * 执行后置处理器SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference()方法尝试获取一个早期的引用。             * 并加入的单例工厂缓存中             * @see DefaultSingletonBeanRegistry#addSingletonFactory(String, ObjectFactory)             * @see #getEarlyBeanReference             */    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));  }  // Initialize the bean instance.  // 初始化bean实例,填充属性,注入依赖(@Autowired,@Resource,@Value)注解的属性  Object exposedObject = bean;  try {    populateBean(beanName, mbd, instanceWrapper);    /**             执行bean的初始化回调方法以及执行后置处理器的初始化方法,包括:            一,执行Aware接口 ,包括BeanFactoryAware,BeanClassLoaderAware,BeanNameAware                注意:ApplicationContext的注入是在另外一个后置处理器ApplicationContextAwareProcessor中执行。              二,执行bean初始化回调,包括:                0. 执行初始化回调BeanPostProcessor.postProcessBeforeInitialization()方法                1. 执行初始化回调@PostConstruct注解定义的方法                 2. 执行初始化回调InitializingBean.afterPropertiesSet()方法                3. 执行初始化回调@Bean(initMethod = "beanInit")定义的初始化方法beanInit()                 4. 执行初始化回调BeanPostProcessor.postProcessAfterInitialization()方法                5. 执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法                按照上述执行顺序执行             */    exposedObject = initializeBean(beanName, exposedObject, mbd);  }  catch (Throwable ex) {    if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {      throw (BeanCreationException) ex;    }    else {      throw new BeanCreationException(        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);    }  }  // 循环依赖检查  if (earlySingletonExposure) {    Object earlySingletonReference = getSingleton(beanName, false);    if (earlySingletonReference != null) {      if (exposedObject == bean) {        exposedObject = earlySingletonReference;      }      else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {        String[] dependentBeans = getDependentBeans(beanName);        Set actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);        for (String dependentBean : dependentBeans) {          if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {            actualDependentBeans.add(dependentBean);          }        }        if (!actualDependentBeans.isEmpty()) {          throw new BeanCurrentlyInCreationException(beanName,                                                     "Bean with name '" + beanName + "' has been injected into other beans [" +                                                     StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +                                                     "] in its raw version as part of a circular reference, but has eventually been " +                                                     "wrapped. This means that said other beans do not use the final version of the " +                                                     "bean. This is often the result of over-eager type matching - consider using " +                                                     "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");        }      }    }  }  // Register bean as disposable.  try {    /**             * 注册bean销毁回调方法,这个方法和前面的initializeBean()方法是对应的。通常情况下初始化方法和销毁方法是同时出现的。             * 比如回调DisposableBean接口的destroy()方法,需要注意的是这里只是注册,并不会执行销毁回调方法。             * 销毁方法的调用是在手动执行容器的关闭方法的时候:             * @see org.springframework.context.support.AbstractApplicationContext#close()             *             * @see AbstractBeanFactory#registerDisposableBeanIfNecessary(String, Object, RootBeanDefinition)             */    registerDisposableBeanIfNecessary(beanName, bean, mbd);  }  catch (BeanDefinitionValidationException ex) {    throw new BeanCreationException(      mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);  }  /**         * 回到调用处:         * @see #createBean(String, RootBeanDefinition, Object[])         */  return exposedObject;}

其中initializeBean(beanName, exposedObject, mbd)这行是本次我们需要关注的,所有的初始化回调都是在这个方法中执行的。

进入这个方法的代码:

/**     * Initialize the given bean instance, applying factory callbacks     * as well as init methods and bean post processors.     *

Called from {@link #createBean} for traditionally defined beans, * and from {@link #initializeBean} for existing bean instances. * 本方法的作用有 * 一,执行Aware接口 ,包括BeanFactoryAware,BeanClassLoaderAware,BeanNameAware * 注意:ApplicationContext的注入是在另外一个后置处理器ApplicationContextAwareProcessor中执行。 * 二,执行bean初始化回调,包括: * 0. 执行初始化回调BeanPostProcessor.postProcessBeforeInitialization()方法 * 1. 执行初始化回调@PostConstruct注解定义的方法 * 2. 执行初始化回调InitializingBean.afterPropertiesSet()方法 * 3. 执行初始化回调@Bean(initMethod = "beanInit")定义的方法 * 4. 执行初始化回调BeanPostProcessor.postProcessAfterInitialization()方法 * 5. 执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法 * 按照上述执行顺序执行 * * @param beanName the bean name in the factory (for debugging purposes) * @param bean the new bean instance we may need to initialize * @param mbd the bean definition that the bean was created with * (can also be {@code null}, if given an existing bean instance) * @return the initialized bean instance (potentially wrapped) * @see BeanNameAware * @see BeanClassLoaderAware * @see BeanFactoryAware * @see #applyBeanPostProcessorsBeforeInitialization * @see #invokeInitMethods * @see #applyBeanPostProcessorsAfterInitialization * 方法调用处: * @see #doCreateBean(String, RootBeanDefinition, Object[]) */protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { // 如果bean实现了XxxAware接口,则调用这些接口的setXxx()方法 if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } /** * 执行后置处理器的postProcessorBeforeInitialization()方法 * 这里会首先执行第一个初始化回调@PostConstruct声明的方法,是这个类实现的 * @see org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization */ Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // 执行InitializingBean接口和自定义的初始化方法(@Bean(initMethod = "beanInit")) invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } /** * 执行后置处理器的postProcessorAfterInitialization()方法 */ if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } /** * 完成各种初始化回调方法,回到调用处: * @see #doCreateBean(String, RootBeanDefinition, Object[]) */ return wrappedBean;}

在此方法中就可以看到初始化回调的执行顺序,首先是applyBeanPostProcessorsBeforeInitialization()这个方法里面会执行@PostContruct注解的方法,是通过后置处理器实现的。

其次是invokeInitMethods()方法,这个方法内会执行的InitializingBean接口的afterPropertiesSet()方法,以及执行在@Bean注解中定义的初始化方法。

最后的是applyBeanPostProcessorsAfterInitialization()方法,这个方法会执行后置处理器接口SmartInitializingSingleton的afterSingletonsInstantiated()方法。

到此解决了一个疑问,不同类型的回调的执行顺序就是在上述代码中设定的。

PostConstruct注解方法的执行

此注解执行的处理类是org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization。

进入此方法。

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  // 获取@PostConstruct注解定义的方法  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;}

这个方法逻辑比较简单,findLifecycleMetadata()把使用了注解@PostConstruct定义的方法包装成LifecycleMetadata,然后在invokeInitMethods()方法中执行。这两个方法的最底层都是通过反射实现的。

回到前面的疑问,@PostConstruct注解的方法为何可以有多个?并且无法控制方法的执行顺序?

第二个疑问,进入findLifecycleMetadata()方法的实现就知道了。

private LifecycleMetadata findLifecycleMetadata(Class> clazz) {  if (this.lifecycleMetadataCache == null) {    // Happens after deserialization, during destruction...    return buildLifecycleMetadata(clazz);  }  // Quick check on the concurrent map first, with minimal locking.  LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);  if (metadata == null) {    synchronized (this.lifecycleMetadataCache) {      metadata = this.lifecycleMetadataCache.get(clazz);      if (metadata == null) {        // 通过反射获取到使用@PostConstruct注解的方法,并包装成LifecycleMetadata        metadata = buildLifecycleMetadata(clazz);        this.lifecycleMetadataCache.put(clazz, metadata);      }      return metadata;    }  }  return metadata;}

这个方法还不是真正实现的地方,还需要继续进入buildLifecycleMetadata()方法。

private LifecycleMetadata buildLifecycleMetadata(final Class> clazz) {  if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {    return this.emptyLifecycleMetadata;  }  List initMethods = new ArrayList<>();  List destroyMethods = new ArrayList<>();  Class> targetClass = clazz;  do {    final List currInitMethods = new ArrayList<>();    final List currDestroyMethods = new ArrayList<>();    // 通过反射获取到目标类的方法列表,然后遍历这些方法判断是否有使用@PostConstruct注解    // 如果有则保存到currInitMethods    ReflectionUtils.doWithLocalMethods(targetClass, method -> {      if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {        LifecycleElement element = new LifecycleElement(method);        currInitMethods.add(element);        if (logger.isTraceEnabled()) {          logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);        }      }      if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {        currDestroyMethods.add(new LifecycleElement(method));        if (logger.isTraceEnabled()) {          logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);        }      }    });    initMethods.addAll(0, currInitMethods);    destroyMethods.addAll(currDestroyMethods);    targetClass = targetClass.getSuperclass();  }  while (targetClass != null && targetClass != Object.class);  return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :          new LifecycleMetadata(clazz, initMethods, destroyMethods));}

在继续进入doWithLocalMethods()方法, 这个方法还做了一层封装。核心的方法实现在getDeclaredMethods(),这个方法里面最主要一句代码Method[] declaredMethods = clazz.getDeclaredMethods();,这行代码只要用过反射的应该很熟悉。直接通过class获取到类内部的所有方法(包括继承过来的方法)。clazz.getDeclaredMethods()方法返回的是一个数组,里面的元素没有提供排序的入口。所以最终执行的@PostConstruct注解的方法也不知道顺序。

public static void doWithLocalMethods(Class> clazz, MethodCallback mc) {  // 通过反射获取目标类内部的方法  Method[] methods = getDeclaredMethods(clazz, false);  for (Method method : methods) {    try {      mc.doWith(method);    }    catch (IllegalAccessException ex) {      throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);    }  }}

拿到所有注解的方法之后,直接通过for循环逐个执行。从入口一直到这里执行注解方法的过程中,没有对方法做任何的过滤,直接for循环遍历执行。所以同一个类是支持在多个方法上使用@PostConstruct注解,并且会把所有使用了注解的方法执行。

InitializingBean接口执行

@PostConstruct注解的方法执行完毕之后,回到initializeBean()方法中,继续往下执行invokeInitMethods()方法。这个方法中就会执行所有实现了InitializingBean接口的实现类。

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)  throws Throwable {  boolean isInitializingBean = (bean instanceof InitializingBean);  // 使用@PostConstruct定义的方法在解析bean定义时候会初始化到bean定义属性externallyManagedInitMethods里面  // 如果用户在afterPropertiesSet()方法上也使用了@PostConstruct注解则不会再执行。  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) () -> {          ((InitializingBean) bean).afterPropertiesSet();          return null;        }, getAccessControlContext());      }      catch (PrivilegedActionException pae) {        throw pae.getException();      }    }    else {      ((InitializingBean) bean).afterPropertiesSet();    }  }  if (mbd != null && bean.getClass() != NullBean.class) {    // 获取自定义的初始化方法,比如@Bean(initMethod = "beanInit"),自定义的初始化方法就是beanInit()    String initMethodName = mbd.getInitMethodName();    if (StringUtils.hasLength(initMethodName) &&        // 排除自定义的初始化方法也是afterPropertiesSet()方法,避免重复执行        !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&        // 使用@PostConstruct定义的方法在解析bean定义时候会初始化到bean定义属性externallyManagedInitMethods里面        // 方式初始化方法重复执行,如果在前面执行@PostConstruct方法已经执行过同名方法则不再执行        // 另外,如果@Bean自定义的回调方法也是afterPropertiesSet()方法,        // 这里不会再次执行,因为在前面InitializingBean接口方法已经执行过        !mbd.isExternallyManagedInitMethod(initMethodName)) {      invokeCustomInitMethod(beanName, bean, mbd);    }  }}

此方法的逻辑也很明了,分为两部分:前面部分就是判断当前bean是否实现了接口,如果是就直接执行接口的afterPropertiesSet()方法。

((InitializingBean) bean).afterPropertiesSet();

但是在执行之前有一段校验逻辑mbd.isExternallyManagedInitMethod("afterPropertiesSet"),这一行代码就是用于判断,如果前面使用@PostConstruct注解声明的方法中已经包含了afterPropertiesSet则不会在执行这个方法。避免重复执行。这也就是为何演示例子中afterPropertiesSet()方法只会执行一遍的原因。并且是在执行@PostConstruct方法列表的时候就执行了。

这个方法的第二部分也同样有校验。在执行@Bean自定义的初始化方法之前也是先判断afterPropertiesSet()方法是否已经执行过。避免@Bean(initMethod = "afterPropertiesSet")这种情况导致方法重复执行。

@Bean中自定义的方法的执行详细逻辑就不贴代码了,最底层也是通过反射执行的。

好了,完成了@Bean自定义方法和InitializingBean接口方法的执行之后,接着回到initializeBean()方法中,继续往下执行applyBeanPostProcessorsAfterInitialization()方法,这个方法主要是执行后置处理器的postProcessAfterInitialization()方法的。和本篇主题无关,不过多解释。

afterSingletonsInstantiated()方法执行

最后就是SmartInitializingSingleton.afterSingletonsInstantiated()方法的执行,此方法的执行和前面的初始化回调不在一个地方,这个方法是在bean实例化完成,并且完成了属性填充之后。才执行的,代码位置在:org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons。

/**     * 实例化所有除了Spring内部的单例(懒加载的、抽象类、非单例的除外)      */@Overridepublic void preInstantiateSingletons() throws BeansException {  // 省略与本篇无关代码    // =========================================================================  // 到此单例bean都已经实例化完毕,紧接着可以对实例对象做一些增强,通过BeanPostProcessor后置处理器增强  // Trigger post-initialization callback for all applicable beans...  // 判断是否有实现了SmartInittializingSingleton的实现类,通常是Spring内部的实现类,也是Spring提供的一个很重要的扩展点  // 初始化操作执行顺序:@PostConstruct是最先被执行的,然后是InitializingBean,最后是SmartInitializingSingleton  for (String beanName : beanNames) {    Object singletonInstance = getSingleton(beanName);    if (singletonInstance instanceof SmartInitializingSingleton) {      final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;      // bean实例化后调用bean的afterSingletonsInstantiated方法,用户可以实现SmartInitializingSingleton接口,      // 在所有bean实例化后做一些自定义的操作,比如重置实例的某些属性,但是要注意只能处理非懒加载的单例bean      if (System.getSecurityManager() != null) {        AccessController.doPrivileged((PrivilegedAction) () -> {          smartSingleton.afterSingletonsInstantiated();          return null;        }, getAccessControlContext());      }      else {        smartSingleton.afterSingletonsInstantiated();      }    }  }}

此处也是一个后置处理器,这个是Spring框架提供的一个对所有bean初始化的入口。前面的初始化回调都是针对某一个bean做得处理。这个是最大的不同之处。只要你实现了此接口方法afterSingletonsInstantiated(),所有的bean在初始化完成之后执行此方法逻辑。

好了,到此总算是把所有的初始化回调介绍完毕。你是否搞懂了呢??

转载地址:https://blog.csdn.net/weixin_32473663/article/details/113630894 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:nhibernate和mysql_利用NHibernate与MySQL交互
下一篇:win10安装ipython_win10环境 ipython app.py 8080 这里为什么是ipython 这步无法启动

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月22日 19时04分38秒