目录
2.更加简单的获取 Bean
2.1 属性注入
2.1.1 属性注入优点
2.1.2 属性注入缺点
2.2 Setter 注入
2.2.1 优点
2.2.2 缺点
2.3 构造方法注入
2.3.1 优点
2.3.2 缺点
2.4 @Resource:另⼀种注入关键字
2.4.1 @Autowired VS @Resource 区别
3.专项训练
获取 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:
org.springframework
spring-beans
5.2.3.RELEASE
org.springframework
spring-context
5.2.3.RELEASE
新建 spring 配置文件spring-config.xml:
新建目录 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());
}
}