spring容器之开启bean的创建之旅

在上篇spring容器之不同scope bean的创建我们在处理原型的过程中遗留了#createBean(String beanName, RootBeanDefinition mbd, Object[] args)方法的讲解,本篇来说一下此方法,该方法为创建bean的入口,直接看代码:

AbstractBeanFactory.java
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException;

这是方法的定义,其中需要三个参数我们分别来说一下参数的用途:

  1. beanName:该参数为创建bean的名字
  2. mbd:合并之后的beanDefinition对象
  3. args:用于构造函数或者工厂方法创建 Bean 实例对象的参数

看完了方法的定义及每个参数的用途,接下来看它的默认实现类

AbstractAutowireCapableBeanFactory
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    if (logger.isTraceEnabled()) {
        logger.trace("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    //根据rootBeanDefinition和beanName去解析bean的class
    //1.如果当前bean的class被解析了
    //1.1. 克隆一份beanDefinition,主要是因为该动态解析的 class 无法保存到到共享的 BeanDefinition
    Class resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    //2.覆盖了RootBeanDefinition的prepareMethodOverrides方法
    try {
        //验证及准备覆盖的方法
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                beanName, "Validation of method overrides failed", ex);
    }

    try {
        //3. 获取一个解析之后的代理bean的实例,而不是真正的bean实例
        //给 BeanPostProcessors 一个机会用来返回一个代理类而不是真正的类实例
        //AOP是基于此处实现的
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                "BeanPostProcessor before instantiation of bean failed", ex);
    }

    try {
        //4.这里才是真正的执行创建bean的方法
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isTraceEnabled()) {
            logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        // A previously detected exception with proper bean creation context already,
        // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
}

从代码中我们大致的分为了4个步骤来完成的,这里简单的总结一下

  1. 通过我们的参数rootBeanDefinition和beanName来解析指定的class
   //根据rootBeanDefinition和beanName去解析bean的class
    //1.如果当前bean的class被解析了
    //1.1. 克隆一份beanDefinition,主要是因为该动态解析的 class 无法保存到到共享的 BeanDefinition
    Class resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

我们跟踪代码来到:

AbstractBeanFactory.java
/**
 * 1.该方法主要的作用是从bean的定义文件中解析bean的class
 * 2.将bean类名解析为class的引用
 * @param mbd 从合并的beanDefinition来确定bean的class
 * @param beanName bean的名称
 * @param typesToMatch 类型是否匹配
 * @return  解析后的bean的class文件
 * @throws CannotLoadBeanClassException
 */
@Nullable
protected Class resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class... typesToMatch)
        throws CannotLoadBeanClassException {

    try {
        //1.判断是否该bean类型的class,如果是返回class
        if (mbd.hasBeanClass()) {
            return mbd.getBeanClass();
        }
        //2. 如果当前解析环境有安全管理器,那么就在此环境下进行bean的class解析
        if (System.getSecurityManager() != null) {
            return AccessController.doPrivileged((PrivilegedExceptionAction>) () ->
                doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
        }
        //3.没有安全管理器,直接去解析class
        else {
            return doResolveBeanClass(mbd, typesToMatch);
        }
    }
    catch (PrivilegedActionException pae) {
        ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
        throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
    }
    catch (ClassNotFoundException ex) {
        throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
    }
    catch (LinkageError err) {
        throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
    }
}

该方法是解析class的过程,简单的来看一下流程

<1>. 首先通过rootBeanDefinition#hasBeanClass()判断该bean是否有class,有的话返回即可
<2>. 获取当前解析环境的安全管理器,在此环境下进行解析class的操作

private Class doResolveBeanClass(RootBeanDefinition mbd, Class... typesToMatch)
        throws ClassNotFoundException {
    //获取当前上下文的类加载器
    ClassLoader beanClassLoader = getBeanClassLoader();
    ClassLoader dynamicLoader = beanClassLoader;
    boolean freshResolve = false;
    //类型检查
    if (!ObjectUtils.isEmpty(typesToMatch)) {
        // When just doing type checks (i.e. not creating an actual instance yet),
        // use the specified temporary class loader (e.g. in a weaving scenario).
        //获取临时的bean的class加载器,用来临时解析bean的class
        ClassLoader tempClassLoader = getTempClassLoader();
        if (tempClassLoader != null) {
            dynamicLoader = tempClassLoader;
            freshResolve = true;
            //tempClassLoader是否是DecoratingClassLoader(用来装饰class加载器)类型的
            if (tempClassLoader instanceof DecoratingClassLoader) {
                DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
                //遍历所有的类型
                //获取类型的类名
                //通过获取到的类名去从dcl排除添自己加
                for (Class typeToMatch : typesToMatch) {
                    dcl.excludeClass(typeToMatch.getName());
                }
            }
        }
    }
    //typesToMatch为null

    //获取当前bean的class名
    String className = mbd.getBeanClassName();
    if (className != null) {
        //对bean进行评估,(可将其解析为对应的表达式)返回其解析的value
        Object evaluated = evaluateBeanDefinitionString(className, mbd);
        //evaluated不是className时做处理
        if (!className.equals(evaluated)) {
            // A dynamically resolved expression, supported as of 4.2...
            //是class类型
            if (evaluated instanceof Class) {
                return (Class) evaluated;
            }
            //是String类型
            else if (evaluated instanceof String) {
                className = (String) evaluated;
                freshResolve = true;
            }
            //都不是的话抛IllegalStateException异常
            else {
                throw new IllegalStateException("Invalid class name expression result: " + evaluated);
            }
        }
        //className为null
        if (freshResolve) {
            // When resolving against a temporary class loader, exit early in order
            // to avoid storing the resolved Class in the bean definition.
            if (dynamicLoader != null) {
                try {
                    //通过制定class名字去加载class
                    return dynamicLoader.loadClass(className);
                }
                catch (ClassNotFoundException ex) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
                    }
                }
            }
            //利用反射来构建class对象
            return ClassUtils.forName(className, dynamicLoader);
        }
    }

    // Resolve regularly, caching the result in the BeanDefinition...
    //定期解析,将结果保存到BeanDefinition中
    return mbd.resolveBeanClass(beanClassLoader);
}

<3>. 在没有安全器时直接解析,解析的过程上面的方法中已经说明,主要是针对于String和class做了处理

  1. 处理override属性

不知道大家还记得之前有篇文章spring容器标签解析之lookup-method和文章spring容器标签解析之replaced-method中我们讲解了spring对lookup-method和replaced-method的解析过程,实际上是将解析中的配置保存到了BeanDefinition的methodOverrides属性中,这里也是同样的类似方法来处理,我们来看代码:

AbstractBeanDefinition.java
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
    // Check that lookup methods exists.

    if (hasMethodOverrides()) {
        Set overrides = getMethodOverrides().getOverrides();
        //同步枷锁
        synchronized (overrides) {
            //遍历执行prepareMethodOverride方法进行验证
            for (MethodOverride mo : overrides) {
                prepareMethodOverride(mo);
            }
        }
    }
}

方法一看很明了,循环执行prepareMethodOverride方法进行处理,我们接着看:

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
    //获取对应类中的方法名的个数
    int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
    if (count == 0) {
        throw new BeanDefinitionValidationException(
                "Invalid method override: no method with name '" + mo.getMethodName() +
                "' on class [" + getBeanClassName() + "]");
    }
    else if (count == 1) {
        // Mark override as not overloaded, to avoid the overhead of arg type checking.
        //进行对MethodOverride没有被覆盖,主要是为了避免参数类型检查的开始
        mo.setOverloaded(false);
    }
}

简单的来总结一下:

  • 首先是获取方法名的个数
    -如果count为0,直接抛BeanDefinitionValidationException异常
  • 如果count为1时,设置没有被覆盖的方法

如果当前类只有一个方法,那么就设置重载该方法没有被重载,这样在后续调用的时候便可以直接使用找到的方法,而不需要进行方法的参数匹配验证了.

  1. 实例化的前置处理

我们可以看到的是在真正创建bean之前通过方法#resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd)来对BeanDefinition中的属性做些前置处理的操作,我们来看代码:

AbstractAutowireCapableBeanFactory.java
//3. 获取一个解析之后的代理bean的实例,而不是真正的bean实例
        //给 BeanPostProcessors 一个机会用来返回一个代理类而不是真正的类实例
        //AOP是基于此处实现的
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }

上述代码中其实有一个很重要的判断,在我们调用#resolveBeforeInstantiation()后实际上返回的是一个代理对象,并非我们想要的真是对象,如果该代理对象不为null,那么它会直接略过后续的Bean的创建而是直接返回代理结果,很关键的一步,这也是AOP功能基于此处实现的,我们接着看获取代理对象的过程:

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    //如果尚未被解析
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            //获取目标的类型
            Class targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                //<1>.前置
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    //<2>.后置
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

在上面的代码中,最重要的是<1>和<2>的处理过程,那关于如何处理的过程这里不再细究,后续来说.

  • 创建bean的过程

当上面实例化前置处理时如果没有获取到对应的代理对象,那么这里就应该走正常的过程就是bean的创建过程,该过程是通过#doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) 方法来实现,我们来看代码:

/**
 * 该方法是真正的创建bean的方法
 * @param beanName 要创建bean的名称
 * @param mbd 定义bean的beanDefinition文件
 * @param args 创建bean时,构造方法所需的参数或者是调用bean工厂时来创建bean所需的参数
 * @return 完成创建之后的bean的实例
 * @throws BeanCreationException
 */
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {

    //实例化bean的过程
    //BeanWrapper是对bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装 bean 的属性描述器
    BeanWrapper instanceWrapper = null;
    //1.如果是单例,从factoryBeanInstanceCache中移除相应的bean实例
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    //2.根据指定的bean使用对应的策略创建新的实例如:工厂方法、构造函数自动注入、简单初始化
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    //获取封装实例对象
    final Object bean = instanceWrapper.getWrappedInstance();
    //获取对应实例对象的类型
    Class beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        //将获取到的bean类型赋值给mbd的resolvedTargetType
        //resolvedTargetType用来保存真实类型bean的类型
        mbd.resolvedTargetType = beanType;
    }

    // Allow post-processors to modify the merged bean definition.
    //3.允许后置处理修改mbd
    synchronized (mbd.postProcessingLock) {
        //postProcessed默认为false,故不能修改,这里取反表示可以修改
        if (!mbd.postProcessed) {
            try {
                //后置处理修改beanDefinition
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }

    //4.对单例模式下的循环依赖进行检查
    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");
        }
        //避免后期循环依赖,提早曝光创建的bean并加入到addSingletonFactory中
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    //初始化bean实例对象
    Object exposedObject = bean;
    try {
        //5. 给bean的实例填充属性,其中,可能存在依赖于其他bean的属性,然后递归初始化bean的依赖
        populateBean(beanName, mbd, instanceWrapper);
        //6. 调用初始化方法
        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);
        }
    }
    //7. 引用问题处理,这里先暴露早期单例引用的bean
    if (earlySingletonExposure) {
        //从缓存注册中获取,这里不允许早期引用的创建
        Object earlySingletonReference = getSingleton(beanName, false);
        //只有在检测到有依赖的情况下,earlySingletonReference才会不为null
        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.");
                }
            }
        }
    }

    //8. 注册bean
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}

简单的来总结下该方法:

  • 在1处进行是否是单例的判断,如果是需要先清除缓存.

  • 在2处调用#createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)方法来实例化bean,于此同时将beanDefinition进行BeanWrapper的转换,其中BeanWrapper是对beanDefinition的包装,位于org.springframework.beans.BeanWrapper包中,详情后续来说.

  • 在3处,MergedBeanDefinitionPostProcessor 的应用.

  • 在4处,单例模式下的循环依赖处理.关于如何处理后面细说.

  • 在5处,给bean进行属性的填充.如何填充后面来说.

  • 在6处,调用 #initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) 方法,初始化 bean .详情见后面

  • 在7处,循环依赖的检查和处理过程.

  • 在8处,完成对DisDisposableBean的注册并返回

关于创建的流程我们大致分了又以上8类,在后续的章节中我们分别来说.

你可能感兴趣的:(spring容器之开启bean的创建之旅)