关于后端:Bean的生命周期

7次阅读

共计 8285 个字符,预计需要花费 21 分钟才能阅读完成。

之前简略记录了下 springBean 的生命周期,最近打开来看了下,发现自己脱漏了很多细节,很多点都连接不上
明天从新翻看《spring 揭秘》,查资料,补了许多细节。心愿可能让本人和大家更容易看懂吧

Bean 的生命周期的齐全实现须要两个阶段

  1. 容器的启动
  2. bean 的实例化过程(涵盖了 bean 生命周期的大部分)

容器启动阶段

  1. 重点是收集到元信息配置信息,即创立 bean 须要的信息(beanDefinition)
    通过 BeanDefinitionReader, 读取到beanDefinition 信息,再通过beanDefinitionRegistry, 将 BeanDefinition 注册到其外面

// 这是 PropertiesBeanDefinitionReader 把从 properties 文件读取到的配置信息,// 通过 BeanDefinitionRegistry 注册 BeanDefinition 的过程
            AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition(parent, className, getBeanClassLoader());
            bd.setScope(scope); // 作用域 默认 singleton
            bd.setAbstract(isAbstract); // 是否是形象 默认 false 如果是形象的,容器不会实例化 bean,而是将 beanDefinition 信息作为其子类应用
            bd.setLazyInit(lazyInit); // 懒加载 默认 false 如果是 false, 容器一启动就会加载 bean
            bd.setConstructorArgumentValues(cas); // 结构参数
            bd.setPropertyValues(pvs); // 属性信息
            getRegistry().registerBeanDefinition(beanName, bd); // 注册 Beandefinition

BeanDefinitionReader 有多种, 包含:

  • PropertiesBeanDefinitionReader 读取 Properties 配置文件
  • GroovyBeanDefinitionReader 读取 Groovy 配置文件
  • XmlBeanDefinitionReader 读取 Xml 配置文件

bean 实例化前 对 beanDefinition 做出自定义批改

BeanFactoryPostProcessor实例化 bean 之前,能够容许批改 beanDefinition 信息,上面是 spring 默认实现的 BeanFactoryPostProcessor 类:

  • PropertyPlaceholderConfigurer容许咱们在 XML 配置文件中应用占位符(PlaceHolder),并将这些占位符所代表的资源独自配置到简略的 properties 文件中来加载
  • PropertyOverrideConfigurer笼罩对象的属性值
  • 咱们能够本人实现 BeanFactoryPostProcessor 依赖注入 beanFactory,批改beanDefinition 信息

bean 实例化阶段

doCreateBean 源码办法(上面仅对 beanFactory 容器做解析,applicationContext 容器其实大同小异)

/**
     * Actually create the specified bean. Pre-creation processing has already happened
     * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
     * <p>Differentiates between default bean instantiation, use of a
     * factory method, and autowiring a constructor.
     * @param beanName the name of the bean
     * @param mbd the merged bean definition for the bean
     * @param args explicit arguments to use for constructor or factory method invocation
     * @return a new instance of the bean
     * @throws BeanCreationException if the bean could not be created
     * @see #instantiateBean
     * @see #instantiateUsingFactoryMethod
     * @see #autowireConstructor
     */
    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        // 实例化 bean
        Object bean = instanceWrapper.getWrappedInstance();
        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 {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.
        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");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
      
        Object exposedObject = bean;
        try {
                        // 填充 bean 对象属性
            populateBean(beanName, mbd, instanceWrapper);
                        //  初始化 bean
            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<String> 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" +
                                "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            // 查看是否实现 DisposableBean 接口,有的话注册销毁回调办法
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }
  1. 首先第一步,调用 createBeanInstance 办法,利用反射调用类的构造方法,实例化 bean,返回 beanWrapper 对象, 再调用 getWrappedInstance 办法失去实例化的 bean,beanWrapper对象具备获取对象属性的性能,所以能够调用 populateBean 用来实现属性填充。
  1. 开始实例化 bean 之前,会查看 bean 有没有实现过 Aware 接口,如果有则实现。

    
    // AbstractAutowireCapableBeanFactory 类中的 initializeBean 办法
    
    private void invokeAwareMethods(String beanName, Object bean) {if (bean instanceof Aware) {
    
             // 如果 Spring 容器检测到以后对象实例实现了该接口,会将该对象实例的 bean 定义对应的 beanName 设置到以后对象实例。if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);
             }
    
             // 如果容器检测到以后对象实例实现了该接口,会将对应加载以后 bean 的 Classloader 注入以后对象实例。// 默认会应用加载 org.springframework.util.ClassUtils 类的 Classloader
             if (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();
                 if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                 }
             }
             if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
             }
    
             // 以上几个 Aware 接口只是针对 BeanFactory 类型的容器而言
         }
     }

对于 ApplicationContext 类型容器,会额定实现几个 Aware 接口

  1. BeanPostProcessor 阶段

BeanPostProcessor 的概念容易与 BeanFactoryPostProcessor 的概念混同。
但只有记住 BeanPostProcessor 是存在于对象实例化阶段,而 BeanFactoryPostProcessor 则是存在于容器启动阶段,这两个概念就比拟容易辨别了。

BeanPostProcessor 有两个须要子类实现的办法

public interface BeanPostProcessor {

    /**
     * 调用 bean 的 init 办法之前做的前置解决
     */
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}

    /**
     * 调用 bean 的 init 办法之后做的前置解决
     */
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}

}

在 initializeBean 办法内能够看到 BeanPostProcessor 的调用程序

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 {
            // 调用实现了 Aware 接口的对象办法
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {

            // BeanPostProcessor 前置解决
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {

            // 调用 bean 的 init 办法
            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 后置解决
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

留神:applcationContext容器中实现 BeanPostProcessor 接口的 postProcessBeforeInitialization 中,会对实现了 Aware 接口的 bean 进行 invoke 调用。
这里和 BeanFactory 有些不同,BeanFactory是在 BeanPostProcessor 之前实现的

  1. InitializingBean 和 init-method

这两个办法都是在 invokeInitMethods 办法里调用,
InitializingBean接口须要实现afterPropertiesSet 办法容许 bean 实例在设置完所有 bean 属性后执行其整体配置验证和最终初始化。
init-method, 对于用户来说能够自定义办法的名称,也能够对立设置所有对象的 initMethod 比拟灵便,防止批改代码,耦合性低。

  1. DisposableBean 与 destroy-method

DisposableBean接口,子类须要实现 destroy 办法,来销毁对象, 只实用于单例对象,不是单例的话,须要交给调用者本人销毁。
destroy-method注册销毁函数,作用和 destroy 办法同理

总结

本文次要讲了 bean 在 BeanFacotry 容器的生命周期,applicationContext 容器略微提了几点不同,applicationContext 容器减少更多的个性,像事件公布监听,国际化信息反对等。
bean 的生命周期次要波及到容器的加载和 bean 的实例化。

容器的加载:

  • 加载资源文件到 beanDefinition(元信息)
  • 调用实现了 BeanFactoryPostProcessor 接口的办法,能够对 beanDefinition 进行批改。

bean 的实例化:

  • 利用反射 +beanDefinition 元信息实例化失去对象
  • populateBean 办法填充属性
  • 测验对象是否实现过 Aware 接口,有则调用其实现
  • 如果对象有实现 BeanPostProcessor 接口,须要先实现前置办法
  • 调用 InitializingBean 和 init-method 办法 如果有实现或标记的话
  • 再调用 BeanPostProcessor 接口的后置办法
  • 最初查看对象是否实现 DisposableBean 与 destroy-method 来销毁 bean(DisposableBean 接口只针对单例 bean)

材料:

《spring 揭秘》王福强

本文由 mdnice 多平台公布

正文完
 0