美文网首页
spring源码解析八(创建单例bean)

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

作者: 为梦想前进 | 来源:发表于2020-07-08 14:53 被阅读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;
    }
    

    ···

    相关文章

      网友评论

          本文标题:spring源码解析八(创建单例bean)

          本文链接:https://www.haomeiwen.com/subject/rvlccktx.html