Spring之@Autowired注解

@Autowired的几种用法

  • 作用在属性上
  • 作用在方法上
  • 作用在构造器上

demo演示

创建三个普通bean

@Component
public class ComponentA {
}

@Component
public class ComponentB {
}

@Component
public class ComponentC {
}

依赖注入

package com.test.model.component;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MixComponent {

    @Autowired
    private ComponentA componentA;

    private ComponentB componentB;

    private ComponentC componentC;

    @Autowired
    public void setComponentB(ComponentB componentB) {
        this.componentB = componentB;
    }

    public MixComponent() {
    }

    @Autowired
    public MixComponent(ComponentC componentC) {
        this.componentC = componentC;
    }
}

主要流程

对@Autowired注解生效的相关BeanPostProcessor是AutowiredAnnotationBeanPostProcessor,它会在bean实例化的多个阶段,对bean进行处理

具体方法

  1. determineCandidateConstructors : 推断构造方法
  2. postProcessMergedBeanDefinition : 发现注入点
  3. postProcessProperties : 属性注入

推断构造方法相关博文 : Spring之推断构造方法

发现注入点

AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata

AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata

private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
    // 判断class是否存在@Autowired、@Value注解,如果不存在,直接就不处理
    if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
        return InjectionMetadata.EMPTY;
    }

    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

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

        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            // 获取field上@Autowired、@Value注解信息
            MergedAnnotation<?> ann = findAutowiredAnnotation(field);
            if (ann != null) {
                // 如果field是static则不处理
                if (Modifier.isStatic(field.getModifiers())) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Autowired annotation is not supported on static fields: " + field);
                    }
                    return;
                }
                // 判断是否必须
                // @Autowired注解:属性required == true表示必须
                // @Value注解:必须
                boolean required = determineRequiredStatus(ann);
                currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
            }
        });

        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                return;
            }
            // 获取method上@Autowired、@Value注解信息
            MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
            if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                // 如果method是static则不处理
                if (Modifier.isStatic(method.getModifiers())) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Autowired annotation is not supported on static methods: " + method);
                    }
                    return;
                }
                // 如果method参数个数是0则不处理
                if (method.getParameterCount() == 0) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Autowired annotation should only be used on methods with parameters: " +
                                method);
                    }
                }
                // 判断是否必须
                // @Autowired注解:属性required == true表示必须
                // @Value注解:必须
                boolean required = determineRequiredStatus(ann);

                // 如果方法是setXxx或者getXxx,则利用Spring自省机制获取PropertyDescriptor对象
                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 InjectionMetadata.forElements(elements, clazz);
}

 小结

如果field或者method上存在@Autowired或者@Value注解,则Spring会将其解析成一个注入点。field会被解析成AutowiredFieldElement,method会被解析成AutowiredMethodElement

注意点

  • field或者method不能是static,否则不处理
  • method的参数个数必须大于0

属性注入

AutowiredAnnotationBeanPostProcessor#postProcessProperties

注意这里的metadata不是我们方法点进去的InjectionMetadata,而是AutowiredAnnotationBeanPostProcessor的内部类

  • AutowiredFieldElement
  • AutowiredMethodElement

AutowiredFieldElement#inject

AutowiredMethodElement#inject

注入Field

AutowiredAnnotationBeanPostProcessor#resolveFieldValue

DefaultListableBeanFactory#resolveDependency

DefaultListableBeanFactory#doResolveDependency

Spring中细节一般都是在doXxx这样的方法中,所以我们要重点关注

1.处理@Value注解

 大概有下列几种用法

  • @Value("${xxx}") : 获取当前环境中名称为xxx的属性值
  • @Value("${xxx:8080}") : 获取当前环境中名称为xxx的属性值,如果不存在,使用默认值8080
  • @Value("${${xxx}}") :假设当前环境中属性xxx的值为yyy,则表达式获取的为环境中名称为yyy的属性值
  • @Value("#{xxx}") : 获取当前容器中名称为xxx的bean

@Value相关博文 : Spring之@Value注解

2.处理集合类依赖

集合类依赖的处理过程我们不重点说明,因为其底层也是调用单体依赖的逻辑,主要演示其用法

创建一个接口和实现其接口的两个bean

public interface Animal {
}

@Component
public class Cat implements Animal {
}

@Component
public class Fish implements Animal {
}

创建类型为House的bean

@Component
public class House {

    @Autowired
    private List<Animal> list;

    @Autowired
    private Map<String, Animal> map;

    @Autowired
    private Animal[] array;
}

查看运行结果

3.处理单体依赖

DefaultListableBeanFactory#findAutowireCandidates

注入特定类型的bean

Spring期望你在注入某些特定类型的bean时候,使用的是它预先设置的bean,而不是用户自定义的bean

相关源码AbstractApplicationContext#prepareBeanFactory

 demo演示

@Component
public class Person {
    
    // 这种情况下会注入Spring容器中的beanFactory
    @Autowired
    private BeanFactory beanFactory;
    
}
添加候选者

什么是SelfReference

@Configuration
public class SelfReference {
    
    // 第一种情况下的selfReference
    @Autowired
    private SelfReference selfReference;

    // 第二种情况下的selfReference
    @Autowired
    private InnerReference innerReference;

    @Bean
    public InnerReference innerReference() {
        return new InnerReference();
    }

    static class InnerReference {

    }
}

isAutowireCandidate

isAutowireCandidate的方法调用栈有很多同名方法,我们分析最核心的一个

DefaultListableBeanFactory#isAutowireCandidate

这里的resolver是的类型是QualifierAnnotationAutowireCandidateResolver

查看类结构

  1. SimpleAutowireCandidateResolver : 判断bd是否是isAutowireCandidate
  2. GenericTypeAwareAutowireCandidateResolver : 处理泛型
  3. QualifierAnnotationAutowireCandidateResolver : 处理@Qualifier注解

BeanDefinitionHolder对象必须满足上述三个类的isAutowireCandidate方法都返回true,才表示此BeanDefinitionHolder对象是一个候选bd

演示SimpleAutowireCandidateResolver#isAutowireCandidate返回false的情况

创建一个类型为Foo的bean,并复用上文代码

@Component
public class Foo {

}

@Component
public class Person {

    // 这种情况下会注入Spring容器中的beanFactory
    @Autowired
    private BeanFactory beanFactory;

    @Autowired(required = false)
    private Foo foo;
}

创建一个bfpp,将foo的AutowireCandidate的值设为false

@Component
public class FirstBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        BeanDefinition beanDefinition = registry.getBeanDefinition("foo");
        // 设置其不是候选者
        beanDefinition.setAutowireCandidate(false);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}

属性foo注入失败

演示会校验泛型的情况

创建Book类,以及实现该类的两个bean

public class Book {
}

@Component
public class EnglishBook extends Book{
}

@Component
public class MathBook extends Book{
}

改造Person代码

@Component
public class Person {
    
    @Autowired
    private List<? extends Book> books;
}

@Qualifier相关博文 : Spring之@Qualifier注解

推断最适合的bean

DefaultListableBeanFactory#determineAutowireCandidate

    protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
        Class<?> requiredType = descriptor.getDependencyType();
        // 如果仅有一个候选者所属class上存在@Primary注解,则返回该候选者
        // 如果存在多个候选者所属class上存在@Primary注解,则抛出异常
        String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
        if (primaryCandidate != null) {
            return primaryCandidate;
        }

        // 判断候选者所属class上是否存在注解@Priority注解
        // 如果存在,返回优先级最高的候选者
        String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
        if (priorityCandidate != null) {
            return priorityCandidate;
        }
        
        // 判断候选者的candidateName和属性名称是否一致,如果一致返回该候选者
        for (Map.Entry<String, Object> entry : candidates.entrySet()) {
            String candidateName = entry.getKey();
            Object beanInstance = entry.getValue();
            if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
                    matchesBeanName(candidateName, descriptor.getDependencyName())) {
                return candidateName;
            }
        }
        return null;
    }

测试代码 

@Component
public class TestBean {

    @Autowired
    private PrimaryTest primaryTest;

    @Autowired
    private PriorityTest priorityTest;

    @Autowired
    private BeanNameTest secondBeanName;
}

public interface PrimaryTest {
}

@Component
@Primary
public class FirstPrimaryBean implements PrimaryTest {
}

@Component
public class SecondPrimaryBean implements PrimaryTest {
}

public interface PriorityTest {
}

@Component
@Priority(1)
public class FirstPriorityBean implements PriorityTest {
}

@Component
@Priority(2)
public class SecondPriorityBean implements PriorityTest {
}

public interface BeanNameTest {
}

@Component
public class FirstBeanName implements BeanNameTest {
}

@Component
public class SecondBeanName implements BeanNameTest {
}

查看运行结果

方法的注入和属性的注入类似,主要还是doResolveDependency方法,这里就不再赘述

整体流程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/471252.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring学习记录之依赖注入

问题1&#xff1a; 往一个类中传递数据的方式有哪些呢&#xff0c;其实&#xff0c;只有一种方式&#xff0c;即通过方法&#xff0c;但方法却有多种&#xff0c;一种是我们先前学到的通过set方法&#xff08;普通方法&#xff09;&#xff0c;另一种则是通过构造方法的方式。…

3.19作业

1、思维导图 2、模拟面试题 1&#xff09;TCP通信中的三次握手和四次挥手 答&#xff1a;三次握手 客户端向服务器发送连接请求 服务器向客户端回复应答并向客户端发送连接请求 客户端回复服务端&#xff0c;并建立联系 四次挥手 进程a向进程b发送断开连接请求…

单例设计模式,各种排序复习

1.单例设计模式 资料来源 1.1单例模式是什么&#xff1f; 单例模式&#xff0c;属于创建类型的一种常用的软件设计模式。 通过单例模式的方法创建的类在当前进程中只有一个实例&#xff08;根据需要&#xff0c;也有可能一个线程中属于单例&#xff0c;如&#xff1a;仅线程…

qt Qt Remote Object(QtRO)实现进程间通信

简介 Qt Remote Object简称QtRO&#xff0c;这是Qt5.9以后官方推出来的新模块&#xff0c;专门用于进程间通信&#xff08;IPC&#xff09;。是基于Socket来封装的&#xff0c;兼容LPC和RPC。LPC即Local Process Communication&#xff0c;而RPC是指Remote Process Communicat…

瑞士百达资产管理有限公司拟增三大去中心化数字加密货币支付接口!

简介: 瑞士百达集团成立于1805年,欧洲第三大财富管理公司, 集团拥有约 5,300 名员工,其中包括 900 名投资经理。它在金融服务中心拥有 30 个办事处网络,包括在日内瓦、卢森堡、拿骚、香港和新加坡的注册银行,百达集团管理的资产总额达6380亿瑞士法郎(7670亿美元)。 瑞士百达资…

触手可及的社交:揭示Facebook如何让每个人都能参与其中

引言 在当今社会&#xff0c;Facebook已经成为了人们日常生活中不可或缺的一部分。无论是与朋友、家人保持联系&#xff0c;还是参与社群讨论、获取新闻信息&#xff0c;Facebook都提供了一个触手可及的社交平台。本文将探讨Facebook如何让每个人都能轻松参与其中&#xff0c;…

ClickHouse01-什么是ClickHouse

什么是ClickHouse&#xff1f; 关于发展历史存在的优势与劣势什么是它风靡的原因&#xff1f; 什么是ClickHouse&#xff1f; 官方给出的回答是&#xff0c;它是一个高性能、列式存储、基于SQL、供在线分析处理的数据库管理系统 当然这边不得不提到OLAP(Online Analytical Pr…

代码随想录day24(1)二叉树:最大二叉树(leetcode654)

题目要求&#xff1a; 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构…

【C++】AVL树的两单旋和两双旋

目录 1. 新节点插入较高左子树的左侧---左左&#xff1a;右单旋 代码 2. 新节点插入较高右子树的右侧---右右&#xff1a;左单旋 代码 3. 新节点插入较高左子树的右侧---左右&#xff1a;先左单旋再右单旋 ​编辑 代码 4. 新节点插入较高右子树的左侧---右左&#xff1a;先…

如何选择适合大功率直流电子负载

选择适合大功率直流电子负载时&#xff0c;需要考虑以下几个关键因素&#xff1a; 功率范围&#xff1a;首先&#xff0c;需要确定所需的最大功率范围。大功率直流电子负载通常有不同的功率等级&#xff0c;如1kW、2kW、5kW等。根据实际应用场景和需求&#xff0c;选择合适的功…

CTF题型 php反序列化进阶(1) php原生类 例题和总结

CTF题型 php反序列化进阶(1) php原生文件操作类 例题和总结 文章目录 CTF题型 php反序列化进阶(1) php原生文件操作类 例题和总结特征原理 我们可以通过PHP自身本来就有的类来进行文件操作扫描目录的三个类DirectoryIterator(支持glob://协议)FilesystemIterator&#xff08;继…

基于springboot的stone音乐播放器的设计与实现

摘 要 随着我国经济的高速发展与人们生活水平的日益提高&#xff0c;人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下&#xff0c;人们更趋向于足不出户解决生活上的问题&#xff0c;stone音乐播放器展现了其蓬勃生命力和广阔的前景。与此同时&#xff0c;…

使用 CSS 实现毛玻璃效果

在现代 Web 设计中,毛玻璃效果越来越受欢迎。它能够让界面元素看起来更加柔和、朦胧,同时又不会完全遮挡背景内容,给人一种透明而又不失质感的视觉体验。虽然过去实现这种效果需要借助图像编辑软件,但现在只需要几行 CSS 代码,就可以在网页上呈现出令人惊艳的毛玻璃效果。 使用…

小火星露谷管理器 报错:“你似乎没有安装Edge的webview2”

错误 解决办法 你可以到这个地方下载安装webview2 https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/?formMT00IS

如何进行汇川PLCH1U-XP系列PLC远程监控?

在工业自动化的浪潮中&#xff0c;可编程逻辑控制器&#xff08;PLC&#xff09;作为控制系统的核心&#xff0c;其稳定性和可靠性对于生产流程的顺畅运行至关重要。汇川PLCH1U-XP系列以其高性能和广泛的应用场景&#xff0c;在工业控制领域占有一席之地。然而&#xff0c;对于…

华为机试真题练习汇总(81~90)

华为机试真题练习汇总&#xff08;81~90&#xff09; 华为机试真题练习汇总&#xff08;81~90&#xff09;HJ81 字符串字符匹配** HJ82 将真分数分解为埃及分数HJ83 二维数组操作HJ84 统计大写字母个数HJ85 最长回文子串HJ86 求最大连续bit数HJ87 密码强度等级* HJ88 扑克牌大小…

2024年 嵌入式系统设计师(中级)

2024年 嵌入式系统设计师全套视频、历年真题及解析、历年真题视频解析、教材、模拟题、重点笔记等资料 1、2023、2022、2021、2020年全套教程精讲视频。 2、嵌入式系统设计师历年真题及解析&#xff08;综合知识、案例分析&#xff09;、历年真题视频解析。 3、官方最新信息嵌…

【爬虫实战】使用Python获取花粉俱乐部中Mate60系列的用户发帖数据

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

每日一题 1969 数组元素的最小非零乘积

1969. 数组元素的最小非零乘积 题目描述&#xff1a; 给你一个正整数 p 。你有一个下标从 1 开始的数组 nums &#xff0c;这个数组包含范围 [1, 2p - 1] 内所有整数的二进制形式&#xff08;两端都 包含&#xff09;。你可以进行以下操作 任意 次&#xff1a; 从 nums 中选…

yolov7 gui 轻松通过GUI来实现车辆行人计数

YOLOv7 GUI 是一款用户友好型图形界面应用程序&#xff0c;专为简化基于YOLOv7&#xff08;You Only Look Once version 7&#xff09;的目标检测流程而设计。该工具允许用户无需深入掌握命令行操作和复杂编程细节&#xff0c;即可方便快捷地运行YOLOv7模型来检测图像或视频中的…