SpringBoot源码解析(二)--自动注入过程(Autowired)

springboot 版本: 2.x
spring 版本 5.x

本篇文章主要分析下 Bean 属性的自动注入过程,并且会概要的分析下 Bean的实例化过程。

在上一篇文章中(https://www.jianshu.com/p/5d75c9bdf0c6)介绍了 springboot启动过程,其中也介绍了 bean的创建时机。其创建代码为 AbstractApplicationContext类refresh()方法中的如下代码:

image.png

Java bean 的初始化以及 field 的注入,都是通过这个方法完成的。

在这之前我们首先要熟悉几个类:
DefaultListableBeanFactory :默认的 bean工厂,看下这个类的继承结构:

image.png

AbstractAutowireCapableBeanFactory:负责创建 bean。
DefaultSingletonBeanRegistry:负责存储已经创建出来的 bean。
AutowiredAnnotationBeanPostProcessor: BeanPostProcessor的派生类, 会被 AbstractAutowireCapableBeanFactory调用并负责注入 bean 的属性。(BeanPostProcessor 的注册时机可以参考上一篇文章https://www.jianshu.com/p/5d75c9bdf0c6)

OK,一些必要的概念已经介绍完了,总结下DefaultListableBeanFactory本质上是一个容器,它会负责创建bean,存储 bean, 还会负责给 bean 注入属性。

接下来 , It's show time.

AbstractApplicationContext finishBeanFactoryInitialization() 方法:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
               // 忽略代码。。。

        // Instantiate all remaining (non-lazy-init) singletons.
        //负责创建非懒加载的单例的bean
        beanFactory.preInstantiateSingletons();
    }

DefaultListableBeanFactory preInstantiateSingletons() 方法:

public void preInstantiateSingletons() throws BeansException {
    //  忽略代码。。。

        // Iterate over a copy to allow for init methods which in turn register new bean definitions.
        // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 获取所有需要通过工程实例化的 bean 定义。
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

        // Trigger initialization of all non-lazy singleton beans...
        for (String beanName : beanNames) {
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//非抽象类, 并且是单例的, 并且是非懒加载的,才会创建
                if (isFactoryBean(beanName)) {
                    //如果是 FactoryBean
                                        //忽略代码。。。
                        
                }
                else {
                          //非 FactoryBean, 也就是我们的 controller、service、dao 等等。。 
                         //创建 bean
                    getBean(beanName);
                }
            }
        }

        // Trigger post-initialization callback for all applicable 
// 忽略代码
    }

进入 getBean 方法,一路跟踪下去

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

进入 AbstractBeanFactory doGetBean()方法

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.
        // 去缓存中获取 bean, 判断 bean 是否已经被创建
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            //忽略代码。。。。。
            
            //如果已经创建了,则直接将sharedInstance转为 bean, 一般情况下(service, controller...)这里的 bean 和sharedInstance指向的是同一个对象
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }  else {
            //如果此 bean 没有被创建,则执行下面常见 bean 的逻辑
            
            // 忽略代码。。。
            
            try {
            
                // 忽略代码。。。 话说 spring 的设计很精妙,但是代码实现确实不算优雅,一个方法太长了。。。。
                // Create bean instance.
                if (mbd.isSingleton()) {
                // 创建 bean, 这里用了 lamda表达式的匿名内部类的实现方式
                // 这个匿名内部类是ObjectFactory, 只有一个方法,getObject(), 其实先就是下面的代码
                // getSingleton()方法里面会调用 objectFactory.getObject()方法,实际执行的也就是createBean()方法。
                    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);
                }
                // 忽略代码。。。。
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }
   //忽略代码。。。
   
   
        return (T) bean;
    }

进入 createBean方法,即AbstractAutowireCapableBeanFactory类的 createBean() 方法

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

        // 忽略一切。。。。
        try {
            //重点部分, 创建 bean
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isDebugEnabled()) {
                logger.debug("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);
        }
    }

进入 doCreateBean()方法,也在AbstractAutowireCapableBeanFactory中。

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) {
        //创建bean, 也就是会调用 bean 的构造方法。 注意,这个方法虽然实例化了 bean,但是并没有给 bean 注入属性
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        
        //忽略代码。。。
        
        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    // 这里会缓存每个 bean的定义,也就是会初始化 bean 的元数据,其中包括 bean 有哪些需要注入的属性,
                    // 跟踪下去会发现其实调用的是AutowiredAnnotationBeanPostProcessor postProcessMergedBeanDefinition()方法
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }
    
      //忽略代码。。。
    
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            // 将实例化好的 bean,添加至缓存,也就是DefaultSingletonBeanRegistry singletonFactories属性中,
            // singletonFactories是一个 map, key 是 beanName, value 是这个 bean 对应的工厂。
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            //此方法才是真正为 bean 注入属性的方法, 并且是递归注入,
            //依赖的是AutowiredAnnotationBeanPostProcessor ,这个类也是 BeanPostProcessor 的派生类。但是经过适配的,主要功能就是执行 autowired。
            //再注入属性实例的过程中,首先会去 DefaultSingletonBeanRegistry 缓存中判断实例是否初始化,如果已经初始化则直接赋值,否则执行上面一些列的 createBean, doCreateBean 方法实例化对象
            //因为实例化和注入是互相不依赖的, 所以即使出现循环依赖的情况: A 依赖 B, B 也依赖 A, 也不会出现问题。 
            //循环依赖的初始化过程如下,1. 初始化 A ; 2. 将 A 加入缓存;  3. 给 A 注入 B 对象; 4. 发现 B 没有初始化, 初始化 B.
            //5. 给 B 注入 A 对象,获取 A 时,发现A 再缓存中, 直接将 A 的实例赋值给B,支持 B 初始化且注入完成。 6. 将 B 的实例注入给 A。
            //至此 完成 A B 的初始化和注入。
            populateBean(beanName, mbd, instanceWrapper);
            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);
            }
        }

        
        // 忽略 忽略。。。。

        return exposedObject;
    }

最后我们来看下是如何找到需要注入的 Autowired 属性的,也就是
AutowiredAnnotationBeanPostProcessor postProcessMergedBeanDefinition()方法

@Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }

进入findAutowiringMetadata()方法

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
//首先判断缓存中是否存在
        InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized (this.injectionMetadataCache) {
                metadata = this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }
//如果不存在则新建元数据
                    metadata = buildAutowiringMetadata(clazz);
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
        return metadata;
    }

进入buildAutowiringMetadata()方法

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
        Class<?> targetClass = clazz;

        do {
            final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();

//又是一个匿名内部类,不过首先是doWithLocalFields()方法通过反射机制找到所有的 field
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
            //再找到被 Autowired注解注释的 field
                AnnotationAttributes ann = findAutowiredAnnotation(field);
                if (ann != null) {
                    if (Modifier.isStatic(field.getModifiers())) {
                        if (logger.isWarnEnabled()) {
                            logger.warn("Autowired annotation is not supported on static fields: " + field);
                        }
                        return;
                    }
                    boolean required = determineRequiredStatus(ann);
                    currElements.add(new AutowiredFieldElement(field, required));
                }
            });

            //忽略代码。。。。
        }
        while (targetClass != null && targetClass != Object.class);

        return new InjectionMetadata(clazz, elements);
    }

进入 ReflectionUtils.doWithLocalFields();

public static void doWithLocalFields(Class<?> clazz, FieldCallback fc) {
        for (Field field : getDeclaredFields(clazz)) {
            try {
                fc.doWith(field);
            }
            catch (IllegalAccessException ex) {
                throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
            }
        }
    }


private static Field[] getDeclaredFields(Class<?> clazz) {
        Assert.notNull(clazz, "Class must not be null");
        Field[] result = declaredFieldsCache.get(clazz);
        if (result == null) {
            try {
//最终还是反射
                result = clazz.getDeclaredFields();
                declaredFieldsCache.put(clazz, (result.length == 0 ? NO_FIELDS : result));
            }
            catch (Throwable ex) {
                throw new IllegalStateException("Failed to introspect Class [" + clazz.getName() +
                        "] from ClassLoader [" + clazz.getClassLoader() + "]", ex);
            }
        }
        return result;
    }

首先通过反射找到所有的 field,再区分出被 autowired注释的 field(本部分比较复杂,本文不做分析了),然后再通过反射给这些 field 的赋值(这部分也比较简单,就是 Invoke 一下 set方法)。bean 的注入就完成了。

还是有很多细节的部分没有分析到,但是面面俱到也不现实,重要是要知道其思想和大致原理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容