Sprint framework Day08:Spring的@Autowired注解

news2024/11/25 20:17:35

前言

当使用注解和 XML 配置结合时,可以使用注解 @Autowired@Qualifier@Primary 来实现自动装配并进行依赖注入。

一、了解 @Autowired@Qualifier@Primary 注解

  1. @Autowired 注解:用于自动装配依赖。在需要进行依赖注入的地方,添加 @Autowired 注解即可。Spring 容器会根据类型找到对应的 Bean,并将其注入到目标对象中。

  2. @Qualifier 注解:用于指定具体的 Bean 进行装配。当存在多个相同类型的 Bean 时,使用 @Autowired 没法区分哪个 Bean 要注入。此时,可以结合 @Qualifier 注解来指定要注入的具体 Bean。

  3. @Primary 注解:用于标记首选的 Bean。当存在多个相同类型的 Bean,但想要优先使用其中的一个 Bean 进行注入时,可以在该 Bean 上添加 @Primary 注解。

 了解了这三个注解是干嘛用的,我们就来写个案例实现一下吧。

二、开始学习 @Autowired

1、新建项目,结构如下

2、导入 spring 依赖 
 
    <!-- spring 的核心依赖 -->
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.23</version>
        </dependency>
 
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.5</version>
        </dependency>
 
 
    </dependencies>
3、在 service 包下新建一个 Userservice 接口,在 impl 包下新建一个 UserServiceImpl 实现类

UserService 接口

public interface UserService {

    void add();

}

UserServiceImpl 实现类


@Slf4j
@Service("userService")
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        log.info("添加用户.....");
    }
}
4、在 controller 包下新建一个 UserController 类

@Controller
public class UserController {

    /**
     * 字段注入 (spring 不推荐从字段注入)
     * 不推荐使用字段注入,不安全
     */
    private UserService userService;


    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }


    public void add() {
        userService.add();
    }

}
5、在 resources 下新建一个 spring 的 xml 文件 application.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 启用包扫描 -->
    <context:component-scan base-package="edu.nf.ch08"/>

</beans>
6、测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

这个案例是一个基于 Spring 框架的示例,展示了使用依赖注入和组件扫描来管理对象和实现控制反转(IoC)的过程。

  • 首先,在 UserServiceImpl 类中使用 @Slf4j 注解引入了一个日志记录器,并使用 @Service("userService") 注解将该类标记为一个服务组件。UserServiceImpl 实现了 UserService 接口,并实现了其中的 add() 方法用于添加用户。
  • UserController 类中,它使用 @Autowired 注解将 UserService 依赖注入到 private UserService userService 字段中。通过构造方法注入,将 UserService 实例传递给 UserController 的构造函数,从而实现了依赖注入。
  • Main 类中,它使用 ApplicationContext 加载了一个应用程序上下文,并通过 context.getBean(UserController.class) 获取了 UserController 的实例。这是通过组件扫描和类路径上的 application.xml 文件中的配置 <context:component-scan base-package="edu.nf.ch08"/> 实现的。
  • 组件扫描是 Spring 框架的一项功能,它会自动扫描指定包中的类,并将带有特定注解(例如 @Service@Controller)的类识别为组件,并进行实例化和管理。这样,就无需手动创建对象和处理对象之间的依赖关系,Spring 框架会自动完成这些工作。

总的来说,这段代码展示了使用 Spring 框架进行对象管理和依赖注入的基本流程,通过组件扫描和注解来简化配置和提高开发效率。

三、开始学习 @Qualifier、@Primary注解

上面的案例是只有一个实现类的情况下使用@Autowired 注解自动装配的,那么如果是有两个或多个实现类的时候该怎么办呢?如果只使用 @Autowired 它是否会成功运行调用方法呢?那我们就继续来完成下面的案例。

1、在上面的基础上在 service 包下的 impl 包下新建一个StudentServiceImpl 实现类

@Slf4j
@Service("studentService")
public class StudentServiceImpl implements UserService {
    @Override
    public void add() {
        log.info("添加学生.....");
    }
}
2、测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

 大家可以发现,我们现在有两个是实现类,并且都装配为 bean,在 UserController 中调用 add()方法,为什么有两个 add() 方法,调用的是添加用户的而不是添加学生的呢?

在这段代码中,Main 类通过应用程序上下文获取了 UserController 类的实例对象,并调用了它的 add() 方法。但是,没有明确指定要使用哪个实现类的实例。因此,在这里执行的方法将由 @Autowired 注解注入的 UserService 实例决定。

  • 如果在 application.xml 配置文件中将 userService 注册为组件,则将注入 UserServiceImpl 的实例,并执行 UserServiceImpl 类中的 add() 方法。
  • 如果将 studentService 注册为组件,则注入 StudentServiceImpl 的实例,并执行 StudentServiceImpl 类中的 add() 方法。

如果既没有注册 userService 也没有注册 studentService,则代码将无法正常工作并抛出异常。

因此,要确定执行哪个方法,需要在 application.xml 文件中明确指定要使用哪个实现类的实例,例如通过 <bean> 元素或 @Component 注解来注册 UserServiceStudentService

如果我们要调用添加学生的add()方法要怎么做呢?

3、使用注解 @Qualifier

有三种方法实现,分别是字段注入、setter方法注入、构造方法注入,不推荐使用字段注入,不安全。

1)字段注入

@Controller
public class UserController {

    /**
     * 字段注入 (spring 不推荐从字段注入)
     * 不推荐使用字段注入,不安全
     */
    @Autowired
    @Qualifier("studentService")
    private UserService userService;


    public void add() {
        userService.add();
    }

}

在这段代码中,UserController 类的 userService 字段上使用了 @Autowired 注解进行依赖注入。但是,为了明确指定要注入的实现类,还使用了 @Qualifier("studentService") 注解。

@Qualifier 注解用于指定要注入的 Bean 的名称或标识,以区分同一接口有多个实现类的情况。在这里,@Qualifier("studentService") 指定了要注入的是名为 "studentService" 的 Bean。

因此,在执行 UserController 类的 add() 方法时,将使用通过 @Autowired@Qualifier("studentService") 注入的 UserService 实例,即 StudentServiceImpl 类的实例。然后,调用该实例的 add() 方法。

测试 
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

 通过使用 @Qualifier 注解,并且指定 bean 为 studentService,就成功的调用到添加学生的方法,那么如果需要使用添加用户的方法怎么办呢?只需要把 studentService 改为 userService 即可。

2)setter 方法注入
@Controller
public class UserController {

    /**
     * 字段注入 (spring 不推荐从字段注入)
     * 不推荐使用字段注入,不安全
     */
    private UserService userService;

    /**
     * set 方法注入
     * @param userService
     */
    @Autowired
    @Qualifier("userService")
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void add() {
        userService.add();
    }

}
测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

同上.... 

 3) 构造方法注入
@Controller
public class UserController {

    /**
     * 字段注入 (spring 不推荐从字段注入)
     * 不推荐使用字段注入,不安全
     */
    private UserService userService;

    @Autowired
    @Qualifier("studentService")
    public UserController(UserService userService) {
        this.userService = userService;
    }


    public void add() {
        userService.add();
    }

}
测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

4、使用 @Primary 注解注入

 同样也有三种方法实现,字段、setter方法、构造方法注入。

1)、更改 StudentServiceImpl 类
@Slf4j
@Service("studentService")
@Primary
public class StudentServiceImpl implements UserService {
    @Override
    public void add() {
        log.info("添加学生.....");
    }
}

在这段代码中,StudentServiceImpl 类上使用了 @Service("studentService") 注解将它标记为组件,并且实现了 UserService 接口。同时,还使用了 @Primary 注解,将该类标记为默认的 Bean 实现。

当有多个实现了相同接口的 Bean 时,通过 @Autowired 注解注入时,默认将注入带有 @Primary 注解的 Bean 实现,如果有多个带有 @Primary 注解的 Bean 实现,则会抛出异常。

因此,在执行 UserController 类的 add() 方法时,由于没有显示地指定要注入哪个实现类,应用程序框架将使用默认的 Bean 实现对 UserService 进行依赖注入,即通过 @Autowired@Primary 注解注入的 UserService 实例,即 StudentServiceImpl 类的实例。然后,调用该实例的 add() 方法。

需要注意的是,如果存在多个 UserService 的实现类都使用了 @Primary 注解,则会抛出异常。确保只有一个实现了 UserService 接口的类被标记为 @Primary

2)通过构造方法注入
@Controller
public class UserController {

    /**
     * 字段注入 (spring 不推荐从字段注入)
     * 不推荐使用字段注入,不安全
     */
    private UserService userService;


    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }


    public void add() {
        userService.add();
    }

}
测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

那么如果想要使用 UserServiceImpl 的 add() 方法呢?

只需要把 StudentServiceImpl 的 @Primary 注解删掉,在 UserServiceImpl 类上加上 @Primary 注解即可。 

四、总结

@Autowired 注解默认是根据类型注入(只有一个实现类),如果存在多个实现类的时候,则是根据参数名称进行注入,如果存在多个实现类并且参数名称不匹配,则会引发异常此时应该结合 @Qualifier 来指定来注入的 bean,但是这个注解只能用在普通的方法上也可以使用 @Primary 注解声明在某个类上实现,这样 spring 就会优先注入这个实现类
从 spring4.2 版本开始,如果使用的是构造方法注入,可以不需要任何的注入注解,默认就按照类型注入

五、gitee 案例

案例完整地址:https://gitee.com/qiu-feng1/spring-framework.git

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jetpack:006-如何使用输入框

文章目录 1. 概念介绍2. 使用方法2.1 TextField2.2 OutlinedTextField 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack中文本组件扩展相关的内容&#xff0c;本章回中主要介绍输入框组件。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xff01; 1. 概念介…

C++笔记--基于C++实现NMS算法

1--完整代码 // g nms.cpp -stdc11 -o nms_test // ./nms_test#include <iostream> #include <vector> #include <algorithm>// 锚框结构体 struct BoundingBox{float x, y, width, height, score; };class NMS{ public:NMS(){};// 非极大值抑制函数std::ve…

华为云云耀云服务器L实例评测|华为云耀云服务器L实例私有库搭建verdaccio(八)

九、华为云耀云服务器L实例私有库搭建verdaccio&#xff1a; Verdaccio 是一个简单的、零配置本地私有 npm 软件包代理注册表。Verdaccio 开箱即用&#xff0c;拥有自己的小型数据库&#xff0c;能够代理其它注册表&#xff08;例如 npmjs.org&#xff09;&#xff0c;缓存下载…

Linux桌面环境(桌面系统)

早期的 Linux 系统都是不带界面的&#xff0c;只能通过命令来管理&#xff0c;比如运行程序、编辑文档、删除文件等。所以&#xff0c;要想熟练使用 Linux&#xff0c;就必须记忆很多命令。 后来随着 Windows 的普及&#xff0c;计算机界面变得越来越漂亮&#xff0c;点点鼠标…

接口测试文档

接口测试的总结文档 第一部分&#xff1a;主要从问题出发&#xff0c;引入接口测试的相关内容并与前端测试进行简单对比&#xff0c;总结两者之前的区别与联系。但该部分只交代了怎么做和如何做&#xff1f;并没有解释为什么要做&#xff1f; 第二部分&#xff1a;主要介绍为什…

企业云盘推荐:哪个更适合您的需求?

企业云盘因其便捷易用的特点&#xff0c;已成为现代企业办公的热门工具之一。 首先&#xff0c;企业云盘提供了可靠的数据存储。与传统的本地存储方式相比&#xff0c;企业云盘将数据存储在云服务器上&#xff0c;具有强大的数据冗余和备份机制&#xff0c;确保数据的安全性和…

【专题】并查集判断冲突

&#xff08;1&#xff09;题目 P1955 [NOI2015] 程序自动分析 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) &#xff08;2&#xff09;解决思路 先排序&#xff0c;把所有e1的操作放在前面&#xff0c;然后再进行e0的操作。在进行e1的操作的时候&#xff0c;我们只要把它…

笔试、面试总结(网络安全与渗透测试)

什么是同源策略&#xff1f; 为了防止不同域在用户浏览器中彼此干扰&#xff0c;浏览器对从不同来源&#xff08;域&#xff09;收到的内容进行隔离。浏览器不允许任何旧有脚本访问一个站点的 cookie&#xff0c;否则 &#xff0c;会话容易被劫持。只有发布 cookie 的站点能够…

用servlet实现一个简单的猜数字游戏。

需要两个页面&#xff0c;一个jsp页面&#xff08;guess.jsp&#xff09;和servlet页面&#xff08;servlet&#xff09;。 一.jsp页面 在jsp页面中需要实现&#xff1a; 1.创建随机数并且保存在session中。 2.做个form表单提交猜的数字给servlet页面。 <%page import&…

电提示找不到api-ms-win-crt-runtime-l1-1-0.dll怎么办,分享快速解决办法

如果在电脑中提示api-ms-win-crt-runtime-l1-1-0.dll找不到或丢失的情况&#xff0c;大家可以来看看这篇文章&#xff0c;能够快速解决api-ms-win-crt-runtime-l1-1-0.dll丢失的问题&#xff0c;一起来看看都有什么办法解决吧。 一&#xff0e;api-ms-win-crt-runtime-l1-1-0.d…

判断多个多边形是否连通(方法一:原理)

重点&#xff1a; 1.将多边形一个一个拎出来判断&#xff0c;以1为开始&#xff0c;后续如果连接&#xff0c;就加入序列&#xff0c;以2开始判断&#xff0c;以此为序。

Python 机器学习入门之逻辑回归

系列文章目录 第一章 Python 机器学习入门之线性回归 第一章 Python 机器学习入门之梯度下降法 第一章 Python 机器学习入门之牛顿法 第二章 Python 机器学习入门之逻辑回归 逻辑回归 系列文章目录前言一、逻辑回归简介二、逻辑回归推导1、问题2、Sigmoid函数3、目标函数3.1 让…

【C语言】对文件的输入输出

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C语言初步学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读1. 什么是文件1.1 程序文件1.2 数据文件1.3 数据流1.4 文件名 2. 文件的分类3. 文件缓冲区4. 文件的打开和关闭4.1 文…

IDEA插件推荐:TabColor

国庆假期&#xff0c;闲来无事&#xff0c;笔者自己开发了一个简易的IDEA插件。 TabColor 这是一个IDEA插件。通过改变核心Tab的颜色&#xff0c;将开发者从一堆Tab的迷茫中解放&#xff01; 安装 IDEA插件安装界面&#xff0c;搜索TabColor&#xff0c;进行安装。从浏览器下…

最详细STM32,cubeMX 点亮 led

这篇文章将详细介绍 如何在 stm32103 板子上点亮一个LED. 文章目录 前言一、开发环境搭建。二、LED 原理图解读三、什么是 GPIO四、cubeMX 配置工程五、解读 cubeMX 生成的代码六、延时函数七、控制引脚状态函数点亮 LED 八、GPIO 的工作模式九、为什么使用推挽输出驱动 LED总结…

云上攻防-云原生篇Docker安全权限环境检测容器逃逸特权模式危险挂载

文章目录 前言1、Docker是干嘛的&#xff1f;2、Docker对于渗透测试影响&#xff1f;3、Docker渗透测试点有那些&#xff1f;4、前渗透-判断在Docker中方式一&#xff1a;查询cgroup信息方式二&#xff1a;检查/.dockerenv文件方式三&#xff1a;检查mount信息方式四&#xff1…

NSDT编辑器实现数字孪生

数字孪生的强大功能来自于将真实世界的资产与真实世界的数据联系起来&#xff0c;因此您可以更好地可视化它们。数字孪生使跨职能团队能够以交互式和沉浸式方式协作设计、构建、测试、部署和操作复杂系统。 如何创建数字孪生&#xff1f; 数字孪生是通过导入概念模型&#xf…

C++学习——对象的内存模型

以下内容源于C语言中文网的学习与整理&#xff0c;非原创&#xff0c;如有侵权请告知删除。 对象被创建时会在栈区或者堆区分配内存。我们直观的认识是&#xff0c;如果创建了 10 个对象&#xff0c;就要分别为这 10 个对象的成员变量和成员函数分配内存&#xff0c;如下图所示…

Realm violation Datapatch 禁用DBV database vault

Datapatch failed with the error ORA-47410: Realm violation for CREATE ROLE (Doc ID 2306010.1)​编辑To Bottom APPLIES TO: Oracle Database - Enterprise Edition - Version 12.1.0.2 and later Oracle Database Cloud Schema Service - Version N/A and later Oracle…

使用LLM在KG上进行复杂的逻辑推理10.12+10.13

使用LLM在KG上进行复杂的逻辑推理 摘要介绍相关工作方法问题格式化邻域检索和逻辑链分解链状推理提示实施细节 摘要 在知识图谱上进行推理是一项具有挑战性的任务&#xff0c;这需要深度理解实体之间复杂的关系和它们关系的逻辑。而当前的方法通常依赖于学习 几何形状 以将实体…