目录
2.4.1 @Autowired VS @Resource 区别
获取 Bean 对象也叫做 对象装配,是把对象取出来放在某个类中,有时候也叫 对象注入
对象装配(对象注入)的实现3种方式:
1️⃣属性注入
2️⃣构造方法注入
3️⃣Setter 注入
使用 @Autowired 实现:首先先根据 getTyoe (从容器中)获取对象,如果只获取一个,那么直接将此对象注入到当前属性上;如果获取多个对象,才会使用 getName (根据名称)进行匹配
1️⃣例如,将 UserRepository 类注入到 UserService 类中:
UserService 类的实现代码如下:
- package com.java.demo.service;
-
- import com.java.demo.dao.UserRepository;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
-
- /**
- * Created with IntelliJ IDEA.
- * Description:
- * User: WJZ
- * Date: 2023-10-16
- * Time: 11:33
- */
- @Service
- public class UserService {
-
- //1.属性注解
- @Autowired //DI(依赖注入)
- private UserRepository userRepository;//从spring当中取到UserRepository,并把它设值给当前变量
-
- public int add() {
- System.out.println("Do UserService add method");
-
- //传统写法
- //UserRepository userRepository = new UserRepository();
- //return userRepository.add();
-
- //spring V1.0
- /*ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
- UserRepository userRepository = context.getBean("userRepository",UserRepository.class);
- return userRepository.add();*/
-
- //spring V2.0
- return userRepository.add();
-
-
- }
- }
UserRepository 类的实现代码如下:
- @Repository
- public class UserRepository {
- public int add() {
- System.out.println("Do UserRepository add method ");
- return 1;
- }
-
- }
获取 UserService 中的 getUser ⽅法:
- class UserServiceTest {
-
- @Test
- void add() {
- ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
- UserService userService = context.getBean("userService", UserService.class);
- userService.add();
- }
- }
2️⃣获取多个对象:
User 类的实现代码如下:
- public class User {
- private String name;
-
- @Override
- public String toString() {
- return "User{" +
- "name='" + name + '\'' +
- '}';
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
- }
将 User 对象存储到 Spring当中:
- @Component
- public class Users {
- @Bean("user1")
- public User user1() {
- User user = new User();
- user.setName("张三");
- return user;
- }
- @Bean("user2")
- public User user2() {
- User user = new User();
- user.setName("李四");
- return user;
- }
- }
在 UserService2 中调用 User 对象(这个对象相同类型存储到 spring 中有两个,则根据 getName (根据名称)进行匹配)
- @Service
- public class UserService2 {
- //属性注入
- @Autowired
- private User user;
-
- public void sayHi() {
- System.out.println(user.toString());
- }
- }
生成 UserService2Test 单元测试:
- class UserService2Test {
-
- @Test
- void sayHi() {
- ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
- UserService2 userService2 = context.getBean("userService2", UserService2.class);
- userService2.sayHi();
- }
- }
上述代码含义:在 @Autowired 中注入 User 对象:User对象放在 Users 当中,Users 存放在 demo 包下,会随着 spring 启动而启动,也就是说 spring 启动的时候,就会在 spring 框架中存 user1 = 张三 和use2 = 李四 (类型都是 User),通过单元测试拿到 UserService2,在UserService2 中注入 User 对象,打印信息
执行 测试类:
获取报错:获取唯一一个bean,但是找到了两个 bean
解决方案:
1️⃣将属性的名字和 Bean 的名字对应上
2️⃣使用 @Autowired 配合 @Qualifier 一起使用
3️⃣使用 @Resource
属性注入最大的优点就是实现简单、使用简单,只需要给变量上添加一个注解(@Autowired),就可以在不 new 对象的情况下,直接获得注入的对象了(这就是 DI 的功能和魅力所在),所以它的优点就是使用简单。
1️⃣无法注入 final 修饰的变量
final 特征
- 被 final 修饰的变量需要直接赋值
- 在构造方法中进行赋值
2️⃣通用性问题:只适用于 IoC 容器
3️⃣更容易违背单一设计原则,因为使用起来比较简单
- //Setter 注入
- @Service
- public class UserService3 {
- private UserRepository userRepository;
-
- @Autowired
- public void setUserRepository(UserRepository userRepository) {
- this.userRepository = userRepository;
- }
-
- public void sayHi() {
- System.out.println("Do UserService3 sayHi method");
- userRepository.add();
- }
- }
通常 Setter 只 Set 一个书属性,所以 Setter 注入更符合单一设计原则
1️⃣无法注入 final 修饰的变量
2️⃣setter 注入的对象可以被修改(setter 本来就是一个方法,有可能被多次调用和修改)
造方法注入是 Spring 官方从 4.x 之后推荐的注入方式
- @Service
- public class UserService4 {
- private UserRepository userRepository;
-
- @Autowired
- public UserService4(UserRepository userRepository) {
- this.userRepository = userRepository;
- }
-
- public void sayHi() {
- System.out.println("Do UserService4 sayHi");
- userRepository.add();
- }
- }
如果当前的类中只有一个构造方法,那么 @Autowired 也可以省略
1️⃣可以注入 final 修饰的变量
2️⃣注入的对象是不会被修改(因为构造方法只会加载一次)
3️⃣构造方法注入可以保证注入对象完全初始化
4️⃣构造方法注入通用性更好
1️⃣写法比属性注入复杂
2️⃣使用构造方法注入,无法解决循环依赖的问题
1️⃣出身不同:@Resource 来自于JDK;@Autowired 来自于 Spring 框架
2️⃣支持的参数不同:@Resource 支持很多参数设;@Autowired 只支持一个参数设置(@Qualifier)
3️⃣使用区别:@Resource 不支持构造方法注入;而 @Autowired 支持构造方法注入
4️⃣idea 兼容性支持不同:使用 @Autowired 在 idea 专业版可能会报错;@Resource 不存在误报的问题
@Autowired来自于 spring,spring 框架是在程序执行之后再执行,不能检测到当前类是否注入(注入是的到 spring 当中)
@Resource:java代码是在程序执行之前执行的,能检测到已经注入
例如:我在开直播,有人先进来可以听到我之前讲的知识,有人后来就听不到我之前讲的知识,但是对于这个知识我已经讲过了,这个知识点是存在的。
在 Spring 项⽬中,通过 main ⽅法获取到 Controller 类,调⽤ Controller ⾥⾯通过注⼊的⽅式调⽤ Service 类,Service 再通过注⼊的⽅式获取到 Repository 类, 类⾥⾯有⼀个⽅法构建⼀个 User 对象,返回给 main ⽅法。Repository ⽆需连接数据库,使⽤伪代码即
创建 Maven项目,添加依赖pom.xml:
- <dependencies>
- <dependency>
- <groupId>org.springframeworkgroupId>
- <artifactId>spring-beansartifactId>
- <version>5.2.3.RELEASEversion>
- dependency>
- <dependency>
- <groupId>org.springframeworkgroupId>
- <artifactId>spring-contextartifactId>
- <version>5.2.3.RELEASEversion>
- dependency>
- dependencies>
新建 spring 配置文件spring-config.xml:
- "1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:content="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">
- <content:component-scan base-package="spring.java.demo">content:component-scan>
- beans>
新建目录 spring.java.demo:
在新建 repository.UserRepository 类之前需要有一个 User 对象,新建 model.User 类:
- public class User {
- private int id;
- private String name;
-
- @Override
- public String toString() {
- return "User{" +
- "id=" + id +
- ", name='" + name + '\'' +
- '}';
- }
-
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
- }
新建 repository.UserRepository 类:
- @Repository
- public class UserRepository {
- public User getUser() {
- User user = new User();
- user.setId(1);
- user.setName("张三");
- return user;
- }
- }
新建 service.UserService 类(只是业务组装):
- @Service
- public class UserService {
- @Autowired
- private UserRepository userRepository;
-
- public User getUser() {
- return userRepository.getUser();
- }
- }
新建 controller.UserController 类:
- @Controller
- public class UserController {
- @Autowired
- private UserService userService;
-
- public User getUser() {
- return userService.getUser();
- }
- }
全局类(启动类)User:
- /**
- * 启动类
- */
- public class App {
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
- UserController userController = context.getBean("userController", UserController.class);
- System.out.println(userController.getUser());
- }
- }