spring高质量系列-IOC (六)

本章目标
1.getBean方法的解析
2.@propertySource和@ConfigurationProperties生效的问题.
3.后期还会解析其内嵌式tomcat如何运作
4.解析整个整个spring容器的运转流程
5.总结整个springboot启动流程的总结
6.用processon画上面的流程图

getBean调用的是AbstractBeanFactory的doGetBean方法,实际生产bean的方法是AbstractAutowireCapableBeanFactory类的createBean

具体源码如下:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

        final String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

            try {
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        try {
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }

                // Create bean instance.
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName,
                                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                ex);
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // Check if required type matches the type of the actual bean instance.
        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            }
            catch (TypeMismatchException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Failed to convert bean '" + name + "' to required type '" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T) bean;
    }

  • 1.transformedBeanName是去掉原始的beanName的&然后拿到修改后的beanName去循环获取别名从而找到最终beanName
    1. 然后调用getSingleton(beanName)去获取beanInstance,此时allowEarlyReference=true
  • 3.如果beanInstance获取成功就调用getObjectForBeanInstance,该方法是判断是否返回bean本身还是factorybean,具体逻辑如下
protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

如果name包含&然后看beanInstacne是否可以返回,如果返回的实例不等factoryBean,就抛出异常
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            if (beanInstance instanceof NullBean) {
                return beanInstance;
            }
            if (!(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
            }
        }

到这一步就是要么name不包含&但是生产的bean不是factroybean,要么就是包含&生成的是factorybean本身
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }

        Object object = null;
        if (mbd == null) {
尝试从factoryBeanObjectCache获取真正的对象
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            // 获取失败到这边我们已经可以确定beanInstance就是factorybean
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
          获取merged的bean
            if (mbd == null && containsBeanDefinition(beanName)) {
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }
  • 3.如果beanInstance为null,且isPrototypeCurrentlyInCreation为true代表遇到了原型(非单例)循环依赖,所以抛出异常

循环依赖的总结:

  • 1、首先无论是单例还是原型都不支持构造函数注入的循环依赖,具体原因就是因为是依靠构造函数的,所有bean永远无法实例化成功,从而无法获取bean(原型需要主动调用bean才会触发异常)
  • 2.对于原型bean的其他循环依赖注入也无法支持,因为原型的bean, spring 是不缓存,所以永远都无法获取到在构造函数中依赖的bean
  • 3.对于单例非构造函数的依赖注入,通过提前将实例化但是未初始化bean缓存起来,等到依赖的双方都实例化,互相赋值然后互相填补bean的属性。

  • 4.isPrototypeCurrentlyInCreation的逻辑就是:prototypesCurrentlyInCreation是一个threadlocal,因为是prototype,所以检测每一次请求生成的bean是否存在循环依赖,prototypesCurrentlyInCreation第一次存放的是第一次请求的name字符串,第二次是存放set集合,一会每次请求bean看看set集合是否存在,如果存在代表这个bean已经创建了 但是还是需要重新创建 说明此时存在循环依赖(包含构造函数和setter)
    之所以用threadlocal就是一次请求一个bean理应只生成一次,如果生成多次则存在循环调用
  • 5.检测是否存在父类工厂,如果存在且beanName也不在子类工厂,则调用父类的beanFactory的getBean方法
    1. markBeanAsCreated(beanName);如果创建bean不是为了类型检查,则要标记当前bean已经被创建或者即将被创建以便于BeanFactory可以优化重复创建的bean的缓存 .
  • 7.第六步也就是将beanName放入alreadyCreated,并从mergedBeanDefinitions删除该beanName对应的rootBeanDefinition
    1. 继续获取合并后的MergedLocalBeanDefinition,若该MergedLocalBeanDefinition是抽象类则抛出异常
  • 9.获取某个beanDefinition的dependsOn,这个可以放在xml的bean标签或者@DependsOn 但是如果使用注解 那么该bean必须也是用注解生成 用xml 没有反应,<bean>标签的其他属性都是以单独的注解呈现出来的 不是和@Bean注解在一起比如 @Scope 等
    1. isDependent的逻辑首先检测hashset是否已经存在,如果存在就说明不是循环依赖(这边是循环依赖,之前讲的是循环依赖注入),然后从dependentBeanMap获取当前beanName的依赖哪些beanName,然后看当前beanName和缓存中的beanName是否相同,相同就是循环依赖,让没有但是该beanName还是有其他的依赖beanName,然后检测剩余依赖的beanName是否依赖dependentBeanName,如果有就抛出异常
  • 11.registerDependentBean的就是创建dependentBeanMap和dependenciesForBeanMap两个缓存,他们的value是set,然后将当前的beanName和dependentBeanName分别以key和value 以及value和key的注入这两个缓存中
  • 12 然后在获取dependentBeanName的bean即调用getBean(dependentBeanName)。
  • 13.根据MergedLocalBeanDefinition的scope来进行生产bean,scope分为SCOPE_PROTOTYPE,SCOPE_SINGLETON,SCOPE_REQUEST,SCOPE_SESSION,ScopedProxyMode(Default,No,INTERFACES,TARGET_CLASS)
    1. spring生产bean 分为 sigleton,prototype和其他
  • 15.单例的时候调用getSingleton(String beanName, ObjectFactory<?> singletonFactory) 这个时候也包含proxy,singletonFactory最终调用的是AbstractAutowireCapableBeanFactory的createBean,getSingleton的方法逻辑是:

1.锁定singletonObjects,然后检测缓存中是否包含beanName对应的bean,如果存在直接返回。
2.如果不存在,检测singletonsCurrentlyInDestruction是否为true,true代表该bean正在销毁。
3.inCreationCheckExclusions代表是否需要检测bean正在创建,singletonsCurrentlyInCreation代表单例正在创建的bean,即如果当前的beanName是需要创建检测的,且未正在创建才可以下一步 否则抛出异常
4.然后调用ObjectFactory的getObject方法获取bean
5.在允许创建检测的时候从singletonsCurrentlyInCreation删除当前的beanName然后若bean创建成功则放入singletonObjects和registeredSingletons(放入beanName),删除singletonFactories和earlySingletonObjects

重点createBean

1.不论scope是什么,创建bean都是采用AbstractAutowireCapableBeanFactory的这个方法
2.调用resolveBeanClass得到beanCalss,假如beanDefinition的beanCalss和beanName都不存在且解析后的beanClass存在 ,那么就是用该beanClass进行实例化。
3.resolveBeanClass的逻辑:1.如果原先就有beanClass就立即返回。2.调用doResolveBeanClass方法。
4.doResolveBeanClass的方法逻辑:1.如果typesToMatch存在就把他们的className都放入tempClassLoader的excludedClasses中,即typesToMatch不会去生成class对象。2.获取className,当className为null 直接调用RootBeanDefinition的resolveBeanClass否则 先获取根据scopeName从scopes获取Scope并采用beanExpressionResolver
5.其中beanExpressionResolver是在prepareBeanFactory通过beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));其作用至今没看明白
6.获取到最终的className 然后调用class.forName方法生成class
7.mbdToUse.prepareMethodOverrides();,是检测当前的lookup-method和replace-method,都是通过cglib代理
8.replace-method必须实现MethodReplacer接口的Bean才能替换,而lookup-method则由BeanFactory自动为我们处理了。

public class RootBeanClass implements MethodReplacer {
    public void say() {
        System.out.println("RootBeanClass");
    }

    @Override
    public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName());
        return null;
    }
}
    <bean id="childBeanClass" class="com.marshall.testRooAndChildBeanDefinition.ChildBeanClass">
        <replaced-method name="say" replacer="rootBeanClass"></replaced-method>
    </bean>

    <bean id="rootBeanClass" class="com.marshall.testRooAndChildBeanDefinition.RootBeanClass"
    >

    </bean>

9.这边有个优化就是当我们的look-upmethod or replace-method 没有歧义 即只在父类和父类的中只找到了一个方法名字(这个方法包含方法名字一样但是 参数不一样的) 那么下次就不需要在迭代去寻找了
10.resolveBeforeInstantiation的意思在实例化前解析,通过determineTargetType获取class 获取不到就不往下面执行,determineTargetType(首先尝试从factoryMethod获取class 或者从factory-bean获取beanclass,否则根据className获取class)
在获取到了class之后即给实现了InstantiationAwareBeanPostProcessor接口的bean一次修改bean的机会,InstantiationAwareBeanPostProcessor接口继承了BeanPostProcessor,BeanPostProcessor是在初始化前后进行操作,InstantiationAwareBeanPostProcessor还增加了一个postProcessPropertyValues,大部分默认的实现都是直接返回PropertyValues,只有AutowiredAnnotationBeanPostProcessor 去实现了他 对@Autowire 和@Value 进行了属性注入,如果我们撰写InstantiationAwareBeanPostProcessor 该方法 写了 return null 会导致注入失败,同样postProcessAfterInstantiation如果返回false 也会导致不会继续注入相关属性
11.resolveBeforeInstantiation 是先对bean实例化前进行操作(BeanPostProcessorsBeforeInstantiation),如果实例化成功在调用对bean进行初始化(BeanPostProcessorsAfterInitialization)之所以这样是因为当bean不为空时候不会再调用doGetBean方法去生成bean,此时只有在这有机会调用实例化后的初始化。 此外spring在这里只是对自定义TargetSource生成代理

12.继续分析resolveBeforeInstantiation 如果其得到了bean则直接返回,否则就是调用doCreateBean方法 这个方法就是spring最终生成bean,并且填充bean并完成动态代理的地方

@propertySource和@ConfigurationProperties生效的问题.

1.当执行到AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsBeforeInitialization方法
2.通过调用ConfigurationPropertiesBindingPostProcessor的postProcessBeforeInitialization方法获取@ConfigurationProperties的bean 并对其进行赋值操作

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1.1 Spring IoC容器和bean简介 本章介绍了Spring Framework实现的控制反转(IoC)...
    起名真是难阅读 7,425评论 0 8
  • 1.1 spring IoC容器和beans的简介 Spring 框架的最核心基础的功能是IoC(控制反转)容器,...
    simoscode阅读 11,714评论 2 22
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,179评论 19 139
  • 本文是我自己在秋招复习时的读书笔记,整理的知识点,也是为了防止忘记,尊重劳动成果,转载注明出处哦!如果你也喜欢,那...
    波波波先森阅读 14,219评论 6 86
  • 11月13日 晴 今天是周一,一个新的开始,从今天开始记录可馨的书写,卫生,时间观念等每一项表现,我设计了一个表格...
    可馨和丽丽阅读 1,783评论 0 1

友情链接更多精彩内容