spring源码解析八(创建单例bean)

2020-07-08  本文已影响0人  为梦想前进

上一节,研究了下获取bean的源码,逻辑还是比较简单的,这次,我们一起来研究下创建bean的源码,话不多说,我们直接看源码
发现bean的创建的代码都是在AbstractAutowireCapableBeanFactory这个类中,之前分析@Autowired注解的时候,也是在这个类中
createBean的其他方法我在这里就不分析了,咱们具体就分析doCreateBean

AbstractAutowireCapableBeanFactory

这里将成三个步骤,创建bean实例,填充bean的属性,执行后置处理器,
···
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

    RootBeanDefinition mbdToUse = mbd;

    //确保当前的bean类已经被解析
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }
        mbdToUse.prepareMethodOverrides();

    try {
        //1:在获取bean之前获取一下尝试获取下代理对象
        //2:判断是不是基本类型的对象
        //3:是否需要跳过(获取增强对象,判断存不存在@Aspect注解,存在,证明是AOP类,判断切点,根据@Before等注解获取一个完整的增强对象)
        //4:将获取到的增强对象集合与缓存缓存中的advisor.getName执行比较,如果是同一个bean,直接返回
        //判断是否有自定义的targetSource,存在的话,targetSource以自定义的方式处理目标类,然后返回,否则返回null
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }

    try {
        //真正创建bean实例的方法,
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        return beanInstance;
    }

}

···
这个方法很长,咱们先简单看一下这个方法到底做了什么操作,为了看得清楚,我会删除部分抛异常代码
1:从缓存中获取bean的包装对象并删除缓存
2:缓存中获取不到bean,创建bean实例
3:解决循环依赖
4:填充bean中的属性
5:重新注册一次bean实例
···

AbstractAutowireCapableBeanFactory

doCreateBean

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

    // 1:创建bean包装对象,
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        //如果是单例,从缓存中获取bean包装对象,并删除缓存
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        //创建bean实例,并返回bean包装对象
        //这里创建bean实例并返回bean包装对象
        //createBeanInstance方法中会通过三种方式创建bean实例
        //1:通过工厂方法创建
        //2:通过构造方法注入,比如autowire或者constructor的方式创建bean实例
        //3:通过无参构造的方式创建bean实例
        //4:如果配置文件中配置了lookup-method 和 replace-method,则会利用Cglib代理的方式增强bean实例
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // 后置处理器处理流程,就不展开说了
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            mbd.postProcessed = true;
        }
    }
    //===========================================================================================
    //2.1:判断是否存在循环引用,
    //这个earlySingletonExposure的意思是:单例bean是否提前暴露
    //同时满足三个条件,才会变为true
    //1:mbd.isSingleton():是否是单例
    //2:this.allowCircularReferences:是否循环引用
    //3:isSingletonCurrentlyInCreation:该单例bean是否处于创建中
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        //添加单例工厂对象,用于处理循环引用,这个地方是利用了函数式接口,我们把它展开看,就好看一点
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

        addSingletonFactory(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        // 获取早期bean引用
                        return getEarlyBeanReference(beanName, mbd, bean);
                    }
                });
    }

    //=================================================================================================
    //3:填充属性
    Object exposedObject = bean;
        populateBean(beanName, mbd, instanceWrapper);
        exposedObject = initializeBean(beanName, exposedObject, mbd);

    //2.2解决循环引用
    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 " +
                            "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
            }
        }
    }

    // 必要时再注册一次bean
    registerDisposableBeanIfNecessary(beanName, bean, mbd);

    return exposedObject;
}

···

上一篇下一篇

猜你喜欢

热点阅读