看啥推荐读物
专栏名称: BugPool
根本就没有什么架构师,或者说只要用心,人人都...
目录
相关文章推荐
今天看啥  ›  专栏  ›  BugPool

spring源码日记12: spring创建Bean

BugPool  · 简书  ·  · 2020-02-21 17:36

创建bean前准备

如果使用调试模式,跟进来下面代码倒不会有什么疑问,但是这一步代码的跳转确十分奇特。
在上一节讲到,首先spring在AbstractBeanFactory类中创建了ObjectFactory的对象,并重写了getObject()方法,然后将他传给DefaultSingletonBeanRegistry。此时DefaultSingletonBeanRegistry调用了singletonFactory.getObject(),getObject()又调用了creatBean(),因此实际调用的是AbstractBeanFactory类的creatBean()。而AbstractBeanFactory类又被AbstractAutowireCapableBeanFactory所继承,并且重写了其creatBean(),因此最后调用的就是以下代码

// AbstractAutowireCapableBeanFactory.java
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.
        // 1. 锁定class,确保能根据class,className属性正确获取到对应class
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            // 设置上一步获取到的Class
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            // 2. 校验和准备覆盖的方法(指:lookup-method, replace-method)
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            /**
             * 3. 实例化前的后置处理器
             * 给BeanPostProcessors一个机会返回代理替换调真实的实例,主要是来执行实现了InstantiationAwareBeanPostProcessor接口的BeanPostProcessor
             * AOP核心方法,具体内容到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. 核心逻辑
            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);
        }
    }
  1. 锁定class,首先得告诉spring你要创建的bean是哪个类,这个类存不存在,能不能解析
  2. 检验及准备lookup-method、replace-method方法
    public void prepareMethodOverrides() throws BeanDefinitionValidationException {
        // Check that lookup methods exist and determine their overloaded status.
        if (hasMethodOverrides()) {
            // 循环检查override方法是否存在,有无重载
            getMethodOverrides().getOverrides().forEach(this::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() + "]");
        }
        // 有且仅有1个,则说明没有重载,后续可以直接用。如果有重载后续还得进行解析,看看哪个重载方法最适合
        else if (count == 1) {
            // Mark override as not overloaded, to avoid the overhead of arg type checking.
            mo.setOverloaded(false);
        }
    }
  1. 实例化前置处理,这是目前接触到的第一个后置处理器(墙裂推荐看一下后置处理器的使用: spring BeanPostProcessor 生命周期 ),目前还未开始实例化bean,但是在下一段代码doCreateBean(),将马上开始bean的实例化,因此在这里调用实例化前 后置处理器是合适的。大家到这里只要知道一下后置处理器是怎么用的就行,一般来说这里都是返回null。(需要了解一下AOP的targetSource代理就是在这里完成的,一旦被AOP接手,将通过cglib会生成一个完全不同bean,并且是已经实例化、填充、初始化过的,因此一旦bean不为空则需要应用初始化的后置处理,然后直接返回代理bean,不再继续往下创建。)
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        // 确认bean在初始化阶段之前
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // Make sure bean class is actually resolved at this point.
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                // 确认当前beanName所要返回的最终类型
                Class<?> targetType = determineTargetType(beanName, mbd);
                if (targetType != null) {
                    // 初始化前置处理,在这里
                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                        // 实例化后置处理
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                // 实例化前置处理
                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

上方代码频繁出现InstantiationAwareBeanPostProcessors,该类是一个后置处理器接口。如下,总的有4个方法,1、2两个是用在实例化前后,3、4则是用在属性填充步骤的。也就是说只要有类实现了该接口,且重写了相关方法,则后续所有bean的创建都将被重写的方法所修改。所以后置处理器并不复杂,只是一个调用的过程,难的是有多少子类继承了它,这些子类又进行了哪些处理的操作?比如@Autowired、AOP等等,子类太多肯定无法每个都吃透,后续我们会单独挑出@Autowired详解

InstantiationAwareBeanPostProcessors.png
  1. 看到do了吗,之前说过do才是真正干活的方法!这才是真真真真真核心逻辑。

创建bean

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

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            // 是单例的情况下清空缓存
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            /**
             * 1. 实例化bean,这一阶段是调用构造器生产实例的阶段
             * 
             * 如果有使用@Autowired构造器注入,则在该阶段完成属性的注入。
             * (注意这里是Autowired构造器,而不是我们正常使用的注解在属性上)
             * @Autowired
             * public Outer(Inner inner) {
             *  this.inner = inner;
             * }
             */
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        /**
         *  2. beanDefinition合并后的后置处理
         *  比如@Autowired在属性上,就是在这里解析的,但是仅仅只是单纯的解析,还没有实现注入
         */
        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.
        // 当mbd是单例,且允许循环引用,且正在被创建,则提前曝光该对象
        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");
            }
            // 3. 将该bean提前曝光,具体做法是创建一个ObjectFactory对象,再将对象加入到singletonFactories缓存中
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            //
            /**
             * 4. 填充属性
             * 如果@Autowired注解属性,则在上方完成解析后,在这里完成注入
             *
             * @Autowired
             * private Inner inner;
             */
            populateBean(beanName, mbd, instanceWrapper);
            // 5. 初始化
            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);
            }
        }

        // 6. 被依赖检测
        /**
         * 假设  B, C, D均依赖A,当前正在创建A
         * dependentBeanMap的key = A, value = B, C, D
         * 要检测的是B, C, D是否正确注入了A,而不是要检测A,所以叫被依赖检测
         */
        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                // exposedObject跟bean一样,说明初始化操作没用应用Initialization后置处理器改变exposedObject
                // 注意一下这里用的 == 号,说明是引用是否相等的判断
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                // 引用都不相等了,也就是现在的bean已经不是当时提前曝光的bean了
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    // dependentBeans也就是B, C, D
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    // 循环 B, C, D
                    for (String dependentBean : dependentBeans) {
                        /**
                         * 如果B, C, D已经创建完了,那么他们拿到的肯定是A提前曝光的引用
                         *
                         * 但是这个判断又说明了现在的bean已经不是提前曝光的那个bean了,那这样B, C, D注入的A就是有问题的,抛出异常
                         * 这里有非的条件,里层也个非,需要留心这个逻辑
                         */
                        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 {
            // 7. 根据scope注册bean
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }
  1. 实例化,也就是调用构造函数,new出对应Class对象的过程。其中根据参数类型还分为有参构造函数跟无参构造函数,又根据是否有override函数分为JDK代理和cglib代理。后面做详解
  2. 又是一个后置处理器(再强调一下后置处理器不会用的先看 spring BeanPostProcessor 生命周期 ),跟之前说的一样,只不过是调用子类重写的方法,后面我们详细看一下@Autowired如何通过后置处理器注入属性 spring源码日期16: @Autowired实现原理
  3. 循环依赖提前曝光。在单例模式下,如果允许循环引用,则曝光当前实例。该做法就是当bean只是刚实例化完,还没进行属性填充以及初始化,spring就先将当前实例曝光出去,这样其他bean就可以在当前bean尚未创建完成就获取到当前bean的引用。下一节单独详解
  4. 属性填充,将所有属性填充到bean实例中
  5. 初始化
  6. 被依赖检测(这点了解即可,要看懂不容易,可以考虑学完IOC以后再去深究)。很明显这里多加了一个"被"字!假设B, C, D依赖A,现在正常创建A。如果说B, C, D已经完成了创建,则B, C, D必然已经注入了A,但是被注入的A是提前曝光的版本,现在A经过初始化后变成了新的对象A2(这一步一般是不会发生的),因此B, C, D引用的A是错误的,正确应该引用A2,所以抛出异常。
    做一个测试,让A注入B,B注入A,同时在A初始化时生成一个全新的A。
// 省略getter、setter
public class A {
    @Autowired
    private B b;
}

public class B {
    @Autowired
    private A a;
}

public class ABeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof A) {
            A a = new A();
            a.setB(((A) bean).getB());
            bean = a;
        }
        return bean;
    }
}

// XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="a" class="A"/>
    <bean id="b" class="B"/>

    <bean id="myBeanPostProcessor" class="ABeanPostProcessor"/>
    <context:component-scan base-package="autowire"/>
</beans>

// 报错信息
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Bean with name 'a' has been injected into other beans [b] 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.

  1. 根据不同的scope注册bean,其中destroy-method销毁方法也是在这里注册的

完成创建并返回,接下去会详细介绍上面的步骤,包括循环依赖、实例化、属性填充、初始化、以及@Autowired的注入




原文地址:访问原文地址
快照地址: 访问文章快照