Spring @Autowired注解自动装配过程-程序员宅基地

技术标签: spring  

BeanPostProcessor

在开始之前先介绍一下BeanPostProcessor(后置处理器)BeanPostProcessor接口作用是:在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理。

方法 说明
postProcessBeforeInitialization 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
postProcessAfterInitialization 实例化、依赖注入、初始化完毕时执行
@autowired注解两个个比较重要的类 AbstractAutowireCapableBeanFactory

AbstractAutowireCapableBeanFactory的doCreateBean 主要干了三件事

方法 说明
instantiate bean 实例化 bean
populate bean 为 bean 设置 property 参数
initialize bean 初始化 bean(对创建好的 bean 做一些修饰动作)

该图片取自网络
在这里插入图片描述

现在开始讲解自动装配的流程

第一步:创建bean

方法 说明
AbstractBeanFactory doGetBean 先从缓存中寻找是否存在对应bean,没有则创建
DefaultSingletonBeanRegistry getSingleton 查询是否有对应的单例bean,没有则创建
AbstractAutowireCapableBeanFactory createBean 向下调用创建bean
AbstractAutowireCapableBeanFactory doCreateBean 实例化、填充属性
AbstractAutowireCapableBeanFactory createBeanInstance 向下调用创建bean
AbstractAutowireCapableBeanFactory applyMergedBeanDefinitionPostProcessors 合并bean的处理信息

我们从doCreateBean开始看起

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
        //尝试从缓存中
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }
//如果缓存中没有,则根据对应的策略创建bean(RootBeanDefinition) 
//使用其构造函数 constructor 使用Java 反射实例化了 bean
        if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
		----省略一部分代码----
        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                //第一大步
                //调用MergedBeanDefinitionPostProcessor 后处理器,合并bean的定义信息
            //Autowire等注解信息就是在这一步完成预解析,并且将注解需要的信息放入缓存
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
                }
                mbd.postProcessed = true;
            }
        }
----省略一部分代码----
        try {
        // 对bean属性进行填充,注入bean中的属性,会递归初始化依赖的bean
            this.populateBean(beanName, mbd, instanceWrapper);
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }
        ----省略一部分代码----
  • 第一步 缓存中是否存在bean,若不存在,则根据策略创建bean
  • 第二步 调用MergedBeanDefinitionPostProcessor,预解析@autowired注解的类
  • 第三步 将所有属性都注入到创建的bean中
    再看用于预解析的applyMergedBeanDefinitionPostProcessors方法
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
        Iterator var4 = this.getBeanPostProcessors().iterator();
//循环调用MergedBeanDefinitionPostProcessor接口的类的postProcessMergedBeanDefinition方法
        while(var4.hasNext()) {
            BeanPostProcessor bp = (BeanPostProcessor)var4.next();
            if (bp instanceof MergedBeanDefinitionPostProcessor) {
                MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor)bp;
                bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
            }
        }
    }
 public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        InjectionMetadata metadata = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);
        metadata.checkConfigMembers(beanDefinition);
    }

首先findAutowiringMetadata就是查询构建autowire元数据

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
        String cacheKey = StringUtils.hasLength(beanName)?beanName:clazz.getName();
        InjectionMetadata metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);
        if(InjectionMetadata.needsRefresh(metadata, clazz)) {
            Map var6 = this.injectionMetadataCache;
            synchronized(this.injectionMetadataCache) {
                metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);
                if(InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if(metadata != null) {
                        metadata.clear(pvs);
                    }
 //构建Autowired元数据
                    metadata = this.buildAutowiringMetadata(clazz);
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
 
        return metadata;
    }
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
    
        ArrayList elements = new ArrayList();
        Class targetClass = clazz;
 
        do {
    
            ArrayList currElements = new ArrayList();
            //遍历这个类的所有的field去寻找又Autowired修饰的field
            ReflectionUtils.doWithLocalFields(targetClass, (field) -> {
    
                AnnotationAttributes ann = this.findAutowiredAnnotation(field);
                if(ann != null) {
    
                    //如果这个field是静态static的就警告并停止
                    if(Modifier.isStatic(field.getModifiers())) {
    
                        if(this.logger.isWarnEnabled()) {
    
                            this.logger.warn("Autowired annotation is not supported on static fields: " + field);
                        }
 
                        return;
                    }
                    //这里就取了Autowired的一个required属性,这个属性的作用是
                    //如果这个是false就表明在自动装配的时候没有发现又对应的实例
                    //就跳过去,如果是true没有发现有与之匹配的就会抛出个异常,仅此而已
                    boolean required = this.determineRequiredStatus(ann);
                    currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
                }
 
            });
            //接着是遍历这个类里面的方法
            ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
    
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if(BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
    
                    AnnotationAttributes ann = this.findAutowiredAnnotation(bridgedMethod);
                    //同样的静态方法不能自动装配
                    if(ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
    
                        if(Modifier.isStatic(method.getModifiers())) {
    
                            if(this.logger.isWarnEnabled()) {
    
                                this.logger.warn("Autowired annotation is not supported on static methods: " + method);
                            }
 
                            return;
                        }
 
                        if(method.getParameterCount() == 0 && this.logger.isWarnEnabled()) {
    
                            this.logger.warn("Autowired annotation should only be used on methods with parameters: " + method);
                        }
 
                        boolean required = this.determineRequiredStatus(ann);
                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));
                    }
 
                }
            });
            elements.addAll(0, currElements);
            targetClass = targetClass.getSuperclass();
        } while(targetClass != null && targetClass != Object.class);
        return new InjectionMetadata(clazz, elements);
    }
  • 第一步 将标记@Autowired的字段封装为AutowiredFieldElement对象。
  • 第二步 将标记@Autowired的方法并且此方法是字段的getter或setter方法封装到AutowiredMethodElement对象
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
    
        LinkedHashSet checkedElements = new LinkedHashSet(this.injectedElements.size());
        //injectedElements这个集合就是类里面所有被Autowired修饰过的field或method
        Iterator var3 = this.injectedElements.iterator();
        //遍历这个集合
        //把method或者field放入externallyManagedConfigMembers缓存中
        while(var3.hasNext()) {
    
            InjectionMetadata.InjectedElement element = (InjectionMetadata.InjectedElement)var3.next();
            Member member = element.getMember();
            if(!beanDefinition.isExternallyManagedConfigMember(member)) {
    
                beanDefinition.registerExternallyManagedConfigMember(member);
                checkedElements.add(element);
                if(logger.isDebugEnabled()) {
    
                    logger.debug("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
                }
            }
        }
 
        this.checkedElements = checkedElements;
    }

整个postProcessMergedBeanDefinition的工作就此完成,总结一下就是扫描类中被@autowired注释并且非static的字段域或方法,并且存放到内存中
接下来就要开始属性注入了
即doCreateBean中的populateBean方法

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    
       //如果实例为空但是还有属性,抛出异常
            if(bw == null) {
    
            if(mbd.hasPropertyValues()) {
    
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
        } else {
    
            boolean continueWithPropertyPopulation = true;
            //这边主要是根据InstantiationAwareBeanPostProcessor 判断是否继续给该bean配置属性
            if(!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
    
                Iterator pvs = this.getBeanPostProcessors().iterator();
 
                while(pvs.hasNext()) {
    
                    BeanPostProcessor hasInstAwareBpps = (BeanPostProcessor)pvs.next();
                    if(hasInstAwareBpps instanceof InstantiationAwareBeanPostProcessor) {
    
                        InstantiationAwareBeanPostProcessor needsDepCheck = (InstantiationAwareBeanPostProcessor)hasInstAwareBpps;
                        if(!needsDepCheck.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    
                            continueWithPropertyPopulation = false;
                            break;
                        }
                    }
                }
            }
 
            if(continueWithPropertyPopulation) {
    
                Object pvs1 = mbd.hasPropertyValues()?mbd.getPropertyValues():null;
                //判断如果是按照名字或者类型注入的就进入这条分支
                if(mbd.getResolvedAutowireMode() == 1 || mbd.getResolvedAutowireMode() == 2) {
    
                    MutablePropertyValues hasInstAwareBpps1 = new MutablePropertyValues((PropertyValues)pvs1);
                    if(mbd.getResolvedAutowireMode() == 1) {
    
                        this.autowireByName(beanName, mbd, bw, hasInstAwareBpps1);
                    }
 
                    if(mbd.getResolvedAutowireMode() == 2) {
    
                        this.autowireByType(beanName, mbd, bw, hasInstAwareBpps1);
                    }
 
                    pvs1 = hasInstAwareBpps1;
                }
 
                boolean hasInstAwareBpps2 = this.hasInstantiationAwareBeanPostProcessors();
                boolean needsDepCheck1 = mbd.getDependencyCheck() != 0;
                if(hasInstAwareBpps2 || needsDepCheck1) {
    
                    if(pvs1 == null) {
    
                        pvs1 = mbd.getPropertyValues();
                    }
 
                    PropertyDescriptor[] filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                    if(hasInstAwareBpps2) {
    
                        Iterator var9 = this.getBeanPostProcessors().iterator();
 
                        while(var9.hasNext()) {
    
                            BeanPostProcessor bp = (BeanPostProcessor)var9.next();
//这里循环调用了InstantiationAwareBeanPostProcessor实现类的postProcessPropertyValues
//方法,我们Autowire注解解析类AutowiredAnnotationBeanPostProcessor也是该接口的实现类
                            if(bp instanceof InstantiationAwareBeanPostProcessor) {
    
                                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
                                pvs1 = ibp.postProcessPropertyValues((PropertyValues)pvs1, filteredPds, bw.getWrappedInstance(), beanName);
                                if(pvs1 == null) {
    
                                    return;
                                }
                            }
                        }
                    }
 
                    if(needsDepCheck1) {
    
                        this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs1);
                    }
                }
 
                if(pvs1 != null) {
    
                    this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs1);
                }
            }
        }
    }
最后做个总结

总的来说 IOC自动装配分为三步
第一步:实例化bean
第二步:填充属性参数
第三步:初始化bean

参考博客:
https://blog.csdn.net/nuomizhende45/article/details/84960303

https://www.shangyang.me/2017/04/01/spring-core-container-sourcecode-analysis-beans-instantiating-process/

https://www.shangyang.me/2017/04/05/spring-core-container-sourcecode-analysis-annotation-autowired/

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Refrigeratorma/article/details/104727150

智能推荐

sql 以log形式输出_sqlserver审计日志输出为log格式-程序员宅基地

文章浏览阅读592次。mybatis-config.xml 文件下加上下面这段配置信息就可以了:<settings> <setting name="logImpl" value="STDOUT_LOGGING" /> </setting>=------------------------------------------------------分隔符--------------..._sqlserver审计日志输出为log格式

国外部分音乐人工智能/音乐科技研究机构科研项目简介_斯坦福大学 ccrma 音乐和声学计算机研究中心-程序员宅基地

文章浏览阅读3.9k次,点赞5次,收藏17次。本文对国外部分音乐人工智能/音乐科技科研机构的科研项目与教学课程设置作简要介绍,包括英国伦敦玛丽女王大学(Queen Mary)的数字音乐中心(C4DM)、西班牙巴塞罗那庞培法布拉大学(UPF)的音乐技术研究组(MTG)、美国斯坦福大学的音乐与声学计算机研究中心(CCRMA)以及法国的声学/音乐协调研究所(IRCAM)。_斯坦福大学 ccrma 音乐和声学计算机研究中心

Eclipse插件(RCP)项目搭建_eclipse rcp-程序员宅基地

文章浏览阅读3.1k次,点赞2次,收藏11次。介绍最新的Eclipse RCP 开发工具创建RCP项目的过程。_eclipse rcp

GC算法与分类(Java虚拟机)_gc淘汰机制-程序员宅基地

文章浏览阅读243次。一 . GC算法总结 1.引用计数(淘汰) 2.标记-清除 3.标记-压缩 4.复制算法 -新生代二 . 理解分代思想: 1.依据对象的存活周期进行分类,短命对象为新生代,长命对象归为老年代. 2.根据不同年代的特点,选取合适的收集算法 - 少量对象存活,适合复制算法 - 大量对象存活,适合标记清理或者标记压缩所有的算法,都..._gc淘汰机制

js正则匹配处理样式class style_js 正则替换class样式-程序员宅基地

文章浏览阅读1k次。js使用正在提取样式名和样式内容_js 正则替换class样式

matlab使用笔记_ubuntu matlab 缩放-程序员宅基地

文章浏览阅读806次。下载安装包和破解文件链接: https://pan.baidu.com/s/1X09GAchToEqyMRol3msGAA 密码: wak6–来自百度网盘超级会员V4的分享下载完成后解压右击.iso镜像文件,选择使用其他程序打开选择磁盘映像挂载器打开后会在桌面上看到对应的磁盘,双击打开会进入下图的目录,在该目录右键在终端打开然后在终端输入pwd得到当前路径然后新开一个终端,输入sudo /media/xj/MATHWORKS_R2019A/install不同的电脑sudo后面的路径可能不一样_ubuntu matlab 缩放

随便推点

记录 DataAdapter.Fill 方法 (DataSet) SqlDataAdapter();SqlCommand SqlConnection 类_adapter.fill using哪一个-程序员宅基地

文章浏览阅读1.3k次。 【转自】http://hi.baidu.com/yandavid/blog/item/72006031eddb9418eac4af30.html DataAdapter.Fill 方法 (DataSet) 在 DataSet 中添加或刷新行以匹配使用 DataSet 名称的数据源中的行,并创建一个 DataTable。SqlConnection con = new SqlConne_adapter.fill using哪一个

Windows Server 2016-三种方法备份还原DHCP服务器_win2016的dhcp数据库恢复到2019-程序员宅基地

文章浏览阅读3.6k次。方法一:图形化备份还原DHCP:备份操作:1.DHCP控制台,属性选择”备份”选项:2.指定备份路径,默认是C:\Windows\System32\dhcp\3.备份完成后后,查看备份信息:还原DHCP信息:a.DHCP控制台,属性选择”还原”选项:b.指定对应的配置文件存放位置:c.弹窗选择”是”继续:d.提示需要重启服务,选是继续:..._win2016的dhcp数据库恢复到2019

php上传文件回显,使用input标签和jquery实现多图片的上传和回显功能步骤详解-程序员宅基地

文章浏览阅读189次。这次给大家带来使用input标签和jquery实现多图片的上传和回显功能步骤详解,使用input标签和jquery实现多图片的上传和回显功能的注意事项有哪些,下面就是实战案例,一起来看一下。效果图我们从零来做一个这样的demo第一步:我们先完善一下我们的页面,默认的input-file标签非常丑,我们美化一下它,不会的可以百度一下,就是外面套个盒子,设置input的opacity为0,然后外面的盒..._p.appendchild(img);

lnmp搭建(二)MySQL安装及配置_lnmp 的mysql 配置在那个位置-程序员宅基地

文章浏览阅读1.3k次。lnmp架构之数据库安装及配置一、安装、编译安装包:mysql-boost-5.7.17.tar.gz cmake-2.8.12.2-4.el6.x86_64.rpm1、解压:tar zxf mysql-boost-5.7.17.tar.gz2、编译:cmake -DCMAKE_INSTALL_PREFIX=/usr/local/lnmp/mysql \ ##指向m_lnmp 的mysql 配置在那个位置

制作字库(Bin文件合并 C2BIN)_生成bin字库-程序员宅基地

文章浏览阅读7.6k次。一、点阵文件生成1、使用点阵字库生成器生成文字的点阵信息,采用 UNICODE 编码批量生成。 2、如果具有 C 文件的字库,例如 STM32 开发板的库函数 x:\en.stm32cubef4\STM32Cube_FW_F4_V1.14.0\Utilities\Fonts 中的字库 C 文件,可以使用 C2B转换助手,这个软件可以将 C 文件中的字符数组信息转换成 bin 文件。结果如下图所示:_生成bin字库

linux中recvfrom设置为阻塞,使用选择系统调用的linux阻塞 recvfrom_sockets_开发99编程知识库...-程序员宅基地

文章浏览阅读142次。我有一個UDP客戶機,它必須接收兩個不同的套接字。我正在使用 select 系統調用來複用 recv 調用。但是我看到客戶在第二個 recv 呼叫里被屏蔽了。如何解決這裡問題?struct timeval timeout;timeout.tv_sec = 1;timeout.tv_usec = 0;int activity;FD_ZERO(&socketfds);FD_SET(usocke..._linux 默认recvfrom timeout