@Autowired和@Qualifier

article/2025/11/9 8:20:16

@Autowired 的作用是什么?

1、@Autowired 是一个注释,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。
@Autowired 默认是按照类去匹配,配合 @Qualifier 指定按照名称去装配 bean。

可以这样理解为何需要@Autowired注入,以及@Autowired注释的作用spring可以自动帮你把Bean里面引用的对象的setter/getter方法省略,它会自动帮你set/get(其实是通过反射技术实现的)。
@Autowired注释进行自动注入时,spring容器中匹配的候选Bean数目必须有且仅有一个
当找不到一个匹配的Bean时,spring容器将抛出BeanCreationException异常,并指出必须至少拥有一个匹配的Bean。
如果spring容器中拥有多个候选Bean,spring容器在启动时也会抛出BeanCreationException
这个时候就可以借助@Qualifier注释指定注入Bean的名称,这样@Autowired遇到多个候选Bean的问题也就解决了。

注意:(1.Autowired自动注入如果匹配到多个类型会注入属性名和beanID一致的bean,如果匹配到多个bean且所有bean的id和属性名都不一致,才需要Qualifier注解指定bean的id 2.Autowired不是自动帮我们get/set,他是通过反射直接赋值给属性的)(@Autowired类型相同指的是bean中的class)(在下面的情况中class相同时,需要借助于注解@Qualifier的帮助,通过它提供的name确认需要的注入的哪一个bean)

 

 

<bean name="comment1" class="com.sss.exchanger.Comment">
    <property name="content" value="Content of the 1st comment" />
</bean>

<bean name="comment2" class="com.sss.exchanger.Comment">
    <property name="content" value="Content of the 2nd comment" />
</bean>

 

注解解析器:AutowiredAnnotationBeanPostProcessor

  1. Spring容器启动时,AutowiredAnnotationBeanPostProcessor被注册到容器;
  2. 扫描代码,如果带有@Autowired注解,则将依赖注入信息封装到InjectionMetadata中(见扫描过程);
  3. 创建bean时(实例化对象和初始化),会调用各种BeanPostProcessor对bean初始化,AutowiredAnnotationBeanPostProcessor负责将相关的依赖注入进来;

@Autowired扫描过程

  1. 扫描当前类中标注@Autowired的属性和方法;
  2. 再查找父类中注@Autowired的属性和方法,依次遍历;

 

 

 

1 @Autowired 干嘛的?

用来执行依赖注入.每当一个Spring管理的bean发现有该注解时,会直接注入相应的另一个Spring管理的bean.

1.1 不同地放置有不同作用

  • 属性
    Spring将通过扫描自定义的package或通过在配置文件中直接查找bean
  • 方法
    使用@Autowired注解的每个方法都要用到依赖注入
    但要注意的是,签名中呈现的所有对象都必须是Spring所管理的bean
    如果你有一个方法,比如setTest(Article article, NoSpringArticle noSpringArt) ,其中只有一个参数 (Article article)是由Spring管理的,那么就将抛出一个org.springframework.beans.factory.BeanCreationException异常
    这是由于Spring容器里并没有指定的一个或多个参数所指向的bean,所以也就无法解析它们

1.2 bean的注入方式

  • 名称
    bean解析是通过bean名称
  • 类型
    解析基于bean的类型

1.3 @Qualifier 协作

如下相同类型的bean

<bean name="article1" class="com.sss.Article"><property name="text" value="Content of the 1st Article" />
</bean><bean name="article2" class="com.sss.Article"><property name="text" value="Content of the 2nd Article" />
</bean>

假如只是一个简单的@Autowired,Spring根本不知道你要注入哪个bean。这就需要@Qualifier(value =“beanName”)协作.

譬如,要从 com.javaedge.Article类型的bean中区分article1,article2:

@Qualifier(value="article1")
@Autowired
private Article firstArticle;@Qualifier(value="article2")
@Autowired
private Article secondArticle;

2 优雅地使用@Autowired

启动自动注入

<context:annotation-config />

放在应用程序上下文配置。可以使在遇到@Autowired注解时启用依赖注入

  • bean
// beans first
public class Comment {private String content;public void setContent(String content) {this.content = content;}public String getContent() {return this.content;}}// sample controller
@Controller
public class TestController {@Qualifier(value="comment1")@Autowiredprivate Comment firstComment;@Qualifier(value="comment2")@Autowiredprivate Comment secondComment;@RequestMapping(value = "/test", method = RequestMethod.GET)public String test() {System.out.println("1st comment text: "+firstComment.getText());System.out.println("2nd comment text: "+secondComment.getText());return "test";}}// no-Spring managed class
public class TestNoSpring {@Autowiredprivate Comment comment;public void testComment(String content) {if (comment == null) {System.out.println("Comment's instance wasn't autowired because this class is not Spring-managed bean");} else {comment.setContent(content);System.out.println("Comment's content: "+comment.getContent());}}}
  •  
  • 配置
<bean name="comment1" class="com.sss.exchanger.Comment"><property name="content" value="Content of the 1st comment" />
</bean><bean name="comment2" class="com.sss.exchanger.Comment"><property name="content" value="Content of the 2nd comment" />
</bean>
  •  

打开http://localhost:8080/test来运行TestController
TestController的注解字段正确地自动注入,而TestNoSpring的注解字段并没有注入进去

1st comment text: Content of the 1st comment
2nd comment text: Content of the 2nd comment
Comment's instance wasn't autowired because this class is not Spring-managed bean
  •  

哪里不对 ?TestNoSpring类不由Spring所管理
这就是为什么Spring不能注入Comment实例的依赖

3 隐藏在@Autowired注解背后的秘密

Spring管理可用于整个应用程序的Java对象bean,我们不需要处理他们的生命周期(初始化,销毁)。该任务由此容器来完成。
该上下文具有入口点,在Web应用程序中,是dispatcherservlet
容器(也就是该上下文)会在它那里被启动并且所有的bean都会被注入

看<context:annotation-config />的定义

<xsd:element name="annotation-config"><xsd:annotation><xsd:documentation><![CDATA[Activates various annotations to be detected in bean classes: Spring's @Required and@Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's@PersistenceContext and @PersistenceUnit (if available). Alternatively, you maychoose to activate the individual BeanPostProcessors for those annotations.Note: This tag does not activate processing of Spring's @Transactional or EJB 3's@TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>tag for that purpose.See javadoc for org.springframework.context.annotation.AnnotationConfigApplicationContextfor information on code-based alternatives to bootstrapping annotation-driven support.]]></xsd:documentation></xsd:annotation></xsd:element>
  •  

类内部的注解,如@Autowired、@Value、@Required、@Resource以及Web Serivce相关的注解,是容器对Bean对象实例化和依赖注入时,通过容器中注册的Bean后置处理器处理这些注解的

所以配置了上面这个配置(<context:component-scan>假如有配置这个,那么就可以省略<context:annotation-config />)后,将隐式地向Spring容器注册AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor以及这4个专门用于处理注解的Bean后置处理器。

当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中所有 Bean
当发现 Bean 中拥有@Autowired 注解时就找到和其匹配(默认按类型匹配)的 Bean

并注入到对应的地方中去。

4 源码分析

通过org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor可以实现依赖自动注入
通过这个类来处理@Autowired @Value Spring
它也可以管理JSR-303的@Inject

  • AutowiredAnnotationBeanPostProcessor构造函数中定义要处理的注解

之后,有几种方法对@Autowired处理

第一个,private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz)解析等待自动注入类的所有属性。它通过分析所有字段和方法并初始化org.springframework.beans.factory.annotation.InjectionMetadata类的实例来实现。

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();Class<?> targetClass = clazz;do {final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();//分析所有字段ReflectionUtils.doWithLocalFields(targetClass, field -> {//findAutowiredAnnotation(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));}});//分析所有方法ReflectionUtils.doWithLocalMethods(targetClass, method -> {Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;}AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {if (Modifier.isStatic(method.getModifiers())) {if (logger.isWarnEnabled()) {logger.warn("Autowired annotation is not supported on static methods: " + method);}return;}if (method.getParameterCount() == 0) {if (logger.isWarnEnabled()) {logger.warn("Autowired annotation should only be used on methods with parameters: " +method);}}boolean required = determineRequiredStatus(ann);PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new AutowiredMethodElement(method, required, pd));}});elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);//返回一个InjectionMetadata初始化的对象实例return new InjectionMetadata(clazz, elements);}
.../*** 'Native' processing method for direct calls with an arbitrary target instance,* resolving all of its fields and methods which are annotated with {@code @Autowired}.* @param bean the target instance to process* @throws BeanCreationException if autowiring failed*/public void processInjection(Object bean) throws BeanCreationException {Class<?> clazz = bean.getClass();InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);try {metadata.inject(bean, null, null);}catch (BeanCreationException ex) {throw ex;}catch (Throwable ex) {throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);}}
  •  

InjectionMetadata类包含要注入的元素的列表

注入是通过Java的API Reflection (Field set(Object obj, Object value) 或Method invoke(Object obj,Object … args)方法完成的
此过程直接在AutowiredAnnotationBeanPostProcessor的方法中调用
public void processInjection(Object bean) throws BeanCreationException
它将所有可注入的bean检索为InjectionMetadata实例,并调用它们的inject()方法

public class InjectionMetadata {...
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Collection<InjectedElement> checkedElements = this.checkedElements;Collection<InjectedElement> elementsToIterate =(checkedElements != null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {boolean debug = logger.isDebugEnabled();for (InjectedElement element : elementsToIterate) {if (debug) {logger.debug("Processing injected element of bean '" + beanName + "': " + element);}//看下面静态内部类的方法element.inject(target, beanName, pvs);}}}...public static abstract class InjectedElement {protected final Member member;protected final boolean isField;.../*** Either this or {@link #getResourceToInject} needs to be overridden.*/protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)throws Throwable {if (this.isField) {Field field = (Field) this.member;ReflectionUtils.makeAccessible(field);field.set(target, getResourceToInject(target, requestingBeanName));}else {if (checkPropertySkipping(pvs)) {return;}try {//具体的注入看此处咯Method method = (Method) this.member;ReflectionUtils.makeAccessible(method);method.invoke(target, getResourceToInject(target, requestingBeanName));}catch (InvocationTargetException ex) {throw ex.getTargetException();}}}...}
}
  •  

findAutowiredAnnotation(AccessibleObject ao)

分析属于一个字段或一个方法的所有注解来查找@Autowired注解。如果未找到@Autowired注解,则返回null,字段或方法也就视为不可注入。


http://chatgpt.dhexx.cn/article/uiJKokoX.shtml

相关文章

spring注解@Qualifier的详细用法

环境&#xff1a;springboot2.3.10 一般使用在项目中使用Qualifier来限定注入的Bean。 由于项目中我习惯用Resource注解&#xff0c;所以这里先对Autowired和Resource进行个简单的说明。 Autowired和Resource区别 相同点&#xff1a; Autowired与Resource都可以用来装配Be…

Spring 注解 @Qualifier 详细解析

文章目录 1. 概述2. 痛点3. Qualifier4. Qualifier VS Primary5. 通过名称来自动注入6. 总结 1. 概述 今天带你了解一下 Spring 框架中的 Qualifier 注解&#xff0c;它解决了哪些问题&#xff0c;以及如何使用它。我们还将了解它与 Primary 注解的不同之处。更多的技术解析请…

@Qualifier注解作用

Qualifier 注解作用就是为了给Bean打上一个标记&#xff0c;用来查找bean&#xff0c;代码示例: 创建一个java bean package com.gupaoedu.springcloud.example.demo;public class TestClass {private String name; // getter setter 略 }编写配置类&#xff0c;将这个bean装载…

Spring的注解@Qualifier用法

Spring的注解Qualifier用法 在Controller中需要注入service那么我的这个server有两个实现类如何区分开这两个impl呢&#xff1f; 根据注入资源的注解不同实现的方式有一点小小的区别 下面上铺垫图 请忽略我的红线 ##在Controller中使用 Autowired注入时 Qualifier的意思是合格…

java连接mysql数据库实现图书馆管理系统

图书馆管理系统&#xff0c;具体功能包括&#xff1a; 1. 用户登录 2. 用户注册 3. 新图书入库 4. 图书信息查询 5. 图书更新&#xff08;修改&#xff09; 6. 旧图书删除 7. 办理借阅证登记 8. 图书借阅管理 完整项目&#xff1a;https://download.csdn.net/download/sger123/…

图书馆管理系统(使用数据库实现)

到现在&#xff0c;终于结束了javaSE基础部分的学习。结束前最后一个项目就是使用数据库实现图书管理系统。 整体项目功能流程结构图&#xff1a; 项目开发前的准备&#xff1a; 软件需求说明书 是为了使用户和软件开发者双方对该软件的初始规定有一个共同的理解&…

图书馆管理系统(Java Web)

图书馆管理系统&#xff08;Java Web&#xff09; 概述 基于Spring Spring MVC MyBatis的图书馆管理系统&#xff0c;使用Maven进行包管理。主要功能包括&#xff1a;图书查询、图书管理、图书编辑、读者管理、图书的借阅与归还以及借还日志记录等。 项目演示 演示地址 &…

创建和管理图书管理系统数据库

1&#xff0e; 使用对象资源管理器建立名为“book”的数据库。数据文件和日志文件采用默认方式。 2&#xff0e;使用T-SQL命令建立名为“bookmanager”的数据库&#xff0c;并自定义数据文件和日志文件。 create database bookmanager on primary (namebookmanager_data, file…

数据库课程设计实验报告--图书馆管理系统

一、系统平台 开发工具&#xff1a;Eclipse java Mars 数据库 MySQL server&#xff0c;Navicat可视化工具 操作系统&#xff1a;win10 声明&#xff1a;由于该项目已是四年前大一时所做&#xff0c;时隔已久&#xff0c;且本人已不从事java相关工作&#xff0c;恕不能解答…

图书管理系统 数据库课程实验设计

本课设系软件工程大二学生作&#xff0c;拙笔狂言&#xff0c;恭请斧正。 开发工具&#xff1a;Eclipse 2020-12&#xff0c;Microsoft SQL server 2012 程序语言&#xff1a;Java 引 言 选题题目&#xff1a;图书管理系统 选题背景&#xff1a; &#xff08;1&#xff09;图书…

图书馆管理系统(数据库版)

图书馆管理系统&#xff08;数据库版&#xff09; 目录&#xff1a; 图书馆管理系统&#xff08;数据库版&#xff09;项目框架项目分包数据库列表代码分析工具包所用到的接口&#xff1a; 分享一波&#xff1a;总结&#xff1a; 项目框架 项目分包 上面为本次项目的分包建包示…

图书管理系统(数据库)

一、项目分析 1、项目功能分析 项目功能模块主要分为三个模块&#xff0c;登录模块、管理员模块、操作员模块。 登录模块包括登录功能&#xff0c;注册功能&#xff0c;登录日志功能&#xff0c;修改密码以及找回密码。 管理员模块包括工作日志功能、图书借阅金额设定、操作员…

数据库系统设计大作业:图书馆管理系统

数据库系统设计大作业&#xff1a;图书馆管理系统 参考https://blog.csdn.net/dimo__/article/details/84936685中的设计思路&#xff0c;设计了本系统 1 需求分析 针对图书馆的图书管理系统数据库设计&#xff0c;分别对图书馆的读者、一般工作人员和部门负责人进行详细地分…

简单用数据库实现图书管理系统

目录 一、摘要 2、基本功能 二、前言 三、主体 3.1需求分析 3.1.1 数据需求分析 3.1.2 功能需求分析 3.2概要设计 3.2.1 数据字典 3.2.2 ERD&#xff08;实体关系图&#xff09; 3.2.3 DFD数据流图 3.3 逻辑设计 3.3.1 E-R模型向关系模型的转换规则 3.3.2 E-R图转…

MySQL数据库期末项目 图书馆管理系统

1 项目需求分析 1.1 项目名称 图书馆管理系统 1.2 项目功能 在以前大多部分图书馆都是由人工直接管理&#xff0c;其中每天的业务和操作流程非常繁琐复杂&#xff0c;纸质版的登记信息耗费了大量的人力物力。因此图书馆管理系统应运而生&#xff0c;该系统采用智能化设计&#…

tar文件是什么?怎么解压?

例如在使用coco数据集的时候&#xff0c;下载下来是这样的两个文件&#xff1a; 恕我无知&#xff0c;之前完全没见过这种格式的文件。 经过一番咨询&#xff0c;原来是一种压缩文件&#xff0c;里面藏了很多内容&#xff0c;看它的大小就能猜到。 这种文件一般的压缩软件貌似…

常用的tar解压命令总结

&#xff8d;^ヽ&#xff64;  /⌒&#xff64;  ,   |  &#xffe3;7  (⌒r⌒7/   レ   &#xff3c;/&#xffe3;&#xff3c;&#xff63; &#xff3f;/         { _&#xff8c; ●       ゝ _人   ο  ●  ナ   ト&#xff64;&…

linux中.tar文件怎么解压

linux中.tar文件怎么解压 1、打包压缩tar -cvf etc.tar /app/etc #打包 tar -zcvf pack.tar.gz pack/ #打包压缩为一个.gz格式的压缩包 tar -jcvf pack.tar.bz2 pack/ #打包压缩为一个.bz2格式的压缩包 tar -Jcvf pack.tar.xz pack/ #打包压缩为一个.xz格式的压缩包 2、解…

Linux 解压tar

Linux系统中tar压缩包怎么解压&#xff1f;Linux系统中有一个tar压缩包格式的文件需要解压&#xff0c;但是linux系统中没有找到tar的命令&#xff0c;该怎么办呢&#xff1f;下面我们就来看看详细的教程&#xff0c;需要的朋友可以参考下 在Linux的默认的版本中不是所有的命令…

解压缩命令tar zip rar

文章目录 打包和压缩的概念tar常用独立命令打包压缩查阅tar包内有哪些文件解压缩到指定目录(默认是当前目录)只将tar内的部分文件解压出来其他命令(其他) zip和unziprar和unrar 打包和压缩的概念 tar命令可以为linux的文件和目录创建档案 利用tar&#xff0c;可以为某一特定文件…