spring的自动装配,骚话@Autowired的底层工作原理

  • 时间:
  • 浏览:0

前言

  开心一刻

    十年前,我:我交女票了,比我大两岁。妈:不行!赶紧分!

    八年前,我:我交女票了,比我小两岁,外地的。妈:你就不到让人省点心?

    五年前,我:我交女票了,市长的女儿。妈:别人还能看上你?分了吧!

    今年,我挺着大肚子踏进家门。妈:闺女啊,你终于开窍了 !

前情回顾

  Spring拓展接口之BeanPostProcessor,亲戚亲戚大伙儿来看看它的底层实现中讲到了spring对BeanPostProcessor的底层支持,很久知道了BeanPostProcessor的有一一还还有一个 土法律方法:postProcessBeforeInitialization、postProcessAfterInitialization的执行时机,没看的小伙伴还才能 回过头去看看。从前spring的自动装配是打算插进上一篇博文中全版讲解的,还才能后我其实篇幅机会越多了(细心的小伙伴机会会有从前的表情:,除了几幅图,真没哪几个内容!),既然亲戚亲戚大伙儿都感觉出来了,从前也就明人不说暗话了,并非 没插进上篇讲解,我我其实是机会篇幅越多了(哈哈哈,是有的是很想打我? ); 好了,亲戚亲戚大伙儿言归正传,并非 没插进上篇来讲,篇幅很久原因之一,最主要的原因是发现我犯错了! 犯哪几个错了呢(有的是黄赌毒啊,那是犯罪,我是正人君子!),让人当然了! 理所当然的认为自动装配是在AutowiredAnnotationBeanPostProcessor的postProcessBeforeInitialization或postProcessAfterInitialization中实现的,亲戚亲戚大伙儿来看下AutowiredAnnotationBeanPostProcessor类继承图

  它间接实现了BeanPostProcessor,亲戚亲戚大伙儿再去看下那有一一还还有一个 土法律方法(在父类InstantiationAwareBeanPostProcessorAdapter中)

  竟然啥也没干,很久简单的return bean; 当另一方深以为然的认知被推翻时,那感觉青春恋爱物语毙了狗了 其他自动装配不到和BeanPostProcessor放一块讲,不得不开两篇来分开讲,亲戚亲戚大伙儿都知道:强扭的瓜不甜!

自动装配简单示例

  亲戚亲戚大伙儿先来看有一一还还有一个 简单的自动装配的示例,全版实例代码:spring-boot-BeanPostProcessor

  AnimalConfig

View Code

  AnimalServiceImpl

  AnimalTest

  运行结果

  亲戚亲戚大伙儿在AnimalConfig中很久将Dog、Cat、Pig的实例注册到了spring容器,那为哪几个AnimalServiceImpl实例才能直接应用哪几个实例了,亲戚亲戚大伙儿并不到 手动的将哪几个实例赋值到AnimalServiceImpl实例呀? 这我我其实很久spring提供的自动装配功能,我其实亲戚亲戚大伙儿不到 手动的将哪几个实例赋值到AnimalServiceImpl实例,很久亲戚亲戚大伙儿发现AnimalServiceImpl的属性实例上多了其他注解:@Autowired、@Resource、@Inject,spring通过哪几个注解自动完成了属性实例的注入,而不还要亲戚亲戚大伙儿手动的去赋值了;不到 spring是如何实现自动装配的呢? 亲戚亲戚大伙儿慢慢往下看(注意:后文主要以@Autowired为例来讲解

自动装配源码解析

  AutowiredAnnotationBeanPostProcessor的实例化与注册

    不管为什么会么会说,AutowiredAnnotationBeanPostProcessor终撤出 是有一一还还有一个 BeanPostProcessor,不到 它的实例化与注册(注册到spring的beanFactory)过程与BeanPostProcessor的实例化与注册一样,在spring的启动过程中,刷新上下文(refresh)的完后 ,会调用registerBeanPostProcessors(beanFactory)土法律方法完成BeanPostProcessor的实例化与注册,后续再调用finishBeanFactoryInitialization(beanFactory)实例化非延迟加载的单例bean时,会用到上述注册的BeanPostProcessor

    AutowiredAnnotationBeanPostProcessor的构造土法律方法值得亲戚亲戚大伙儿看看

    默认清况 下,AutowiredAnnotationBeanPostProcessor支持@Autowired和@Value,机会类路径下有java.inject.Inject(也很久引入了javax.inject.jar),不到 也支持@Inject注解,是有的是与亲戚亲戚大伙儿最初的认知其他不一样?。将支持的注解插进了autowiredAnnotationTypes属性中,后续会用到该属性

  bean的实例化与依赖注入

    默认清况 下,spring会把spring容器中的bean当成non-lazy-init singleton来出理 (其他特殊的bean除外),也很久说会在spring的启动过程中就会逐个实例化哪几个bean,并对哪几个bean进行依赖注入;当亲戚亲戚大伙儿真正用到哪几个bean的完后 ,直接用就行,越多再再去实例化,很久用再去注入bean的相关依赖,spring是有的是很厉害?。具体是有的是说的从前,亲戚亲戚大伙儿准备好花生、瓜子和啤酒,好戏即将开始

    亲戚亲戚大伙儿先找到正确的入口,很久用下图省略掉无聊的前戏,直接进入高潮:doCreateBean(不应该是这人 吗,一天天的尽胡思乱想

    doCreateBean内容如下

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实例
        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.
    // 允许后置出理

器来修改bean定义
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                // 调用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition土法律方法
                // AutowiredAnnotationBeanPostProcessor实现了MergedBeanDefinitionPostProcessor,即MergedBeanDefinitionPostProcessor的MergedBeanDefinitionPostProcessor会被调用
                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.
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        // 填充bean,含晒

依赖注入
        populateBean(beanName, mbd, instanceWrapper);
        // 初始化bean,BeanPostProcessor的有一一还还有一个

土法律方法在此中被调用
        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);
        }
    }

    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.");
                }
            }
        }
    }

    // Register bean as disposable.
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}
View Code

    亲戚亲戚大伙儿重点看下posProcessMergedBeanDefinition土法律方法和populateBean土法律方法

  posProcessMergedBeanDefinition

    还才能 看了会读取bean的field和method上的注解,并判断该注解是否在autowiredAnnotationTypes中,机会在则将field封装成AutowiredFiledElement对象、将method封装成AutoWiredMethodElement对象,并存插进InjectionMetadata对象的Set<InjectedElement> checkedElements属性中,最后将该InjectionMetadata对象缓存到了AutowiredAnnotationBeanPostProcessor的Map<String, InjectionMetadata> injectionMetadataCache属性中;说白了很久将bean中被@Autowried(当然还包括@Value、@Inject)修饰的field、method找出来,封装成InjectionMetadata对象并缓存起来,就不到 简单。不仅仅是上图中的animalServiceImpl这有一一还还有一个 bean,spring中所有的非延迟加载的bean都会走这人 创建流程。是有的是很简单,是有的是干劲十足了

  populateBean

    调用AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues土法律方法,从injectionMetadataCache中获取当前bean的依赖信息,比如animalServiceImpl依赖的dog、pig(村里人 机会会有从前的难题:cat呢? cat是被@Resource修饰的,而@Resource有的是由AutowiredAnnotationBeanPostProcessor支持,后续会讲由谁支持),很久逐个将依赖bean注入到目标bean(将dog、pig实例注入到animalServiceImpl实例中);依赖bean从哪来呢?还是从beanFactory中获取,机会不趋于稳定,则又回到bean的创建过程把依赖bean(dog、pig)创建出来,流程与创建animalServiceImpl实例一模一样,也很久在animalServiceImpl实例的依赖注入过程中会把dog、pig对象也创建出来,而有的是等到spring逐个实例化bean的过程中轮到dog、pig才实例化dog、pig,那后续轮到dog、pig时为什么会么会办了,spring会把创建的bean缓存起来,下次就直接从缓存中取了。上图只演示Field的,Method也差不越多,就不演示了,有的是通过反射实现的 。

总结

  1、bean的创建与初始化

    (1)instanceWrapper = createBeanInstance(beanName, mbd, args)  创建目标bean实例;

    (2)applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName)  寻找目标bean的依赖;

    (3)populateBean(beanName, mbd, instanceWrapper)  填充目标bean,完成依赖注入; (这里的循环依赖,有兴趣的还才能 自行去琢磨下)

    (4)initializeBean(beanName, exposedObject, mbd)  初始化目标bean

  2、自动装配与自动配置

    自动配置一般而言说的是spring的@Autowired,是spring的底部形态之一,而自动配置是springboot的@Configuration,是springboot的底部形态之一

  3、Spring支持几下几种自动装配的注解

    @Autowired、@Inject、@Resource以及@Value,用的最多的应该是@Autowired(至少我是从前的),@Inject和@Value也是由AutowiredAnnotationBeanPostProcessor支持,而@Resource是由CommonAnnotationBeanPostProcessor支持(还支持@PostConstruct、@PreDestroy等注解)

    关于@Value与@Autowired,不知道亲戚亲戚大伙儿是否清楚亲戚亲戚大伙儿之间的区别,不清楚的还才能 看看:Spring: @Value vs. @Autowired机会spring的官方文档,总结下:@Value >= @Autowired,很久平时应用中,@Value更多的是用来注入配置值(如:@Value("${db.url}")),而@Autowired则是bean对象的注入

参考

  JAVA 注解的基本原理

  深入理解Spring系列之十四:@Autowired是如何工作的