依赖注入描述的是一个过程,指的是 IoC 容器在创建 Bean 时, 提供运行时所依赖的对象
通俗来讲就是把对象取出来放到某个类的属性中
Spring 提供了三种依赖注入的方式:
- 属性注入(Field Injection)
- 构造方法注入(Constructor Injection)
- Setter 注入(Setter Injection)
下面我们使用这三种方式分别将 Service 类注入到 Controller 类中
属性注入
使用 **
@Autowired
** 实现(autowire 意为自动装配)
@Controller
public class UserController {
@Autowired
private UserService userService;
public void hello() {
System.out.println("UserController...");
userService.hello();
}
}
@Service
public class UserService {
public void hello() {
System.out.println("UserService...");
}
}
@SpringBootApplication
public class ApplicationController {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ApplicationController.class, args);
UserController userController = (UserController) context.getBean("userController");
userController.hello();
}
}
运行结果:
构造方法注入
构造方法注入就是在类的构造方法中注入依赖
@Controller
public class UserController {
private UserService userService;
public void hello() {
System.out.println("UserController...");
userService.hello();
}
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
}
注意:
① 如果类只有一个构造方法,那么 @Autowired 可以省略;如果有多个构造方法,那就需要加上这个注解指定要用哪个构造方法,如果没有指定,默认使用无参的构造方法
② 一般如果自己写了有参构造方法的话,建议把无参的构造方法也写出来
Setter 注入
这个也顾名思义,就是在 setter 方法上加 @Autowired
@Controller
public class UserController {
private UserService userService;
public void hello() {
System.out.println("UserController...");
userService.hello();
}
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
@Service
public class UserService {
public void hello() {
System.out.println("UserService...");
}
}
@SpringBootApplication
public class ApplicationController {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ApplicationController.class, args);
UserController userController = (UserController) context.getBean("userController");
userController.hello();
}
}
运行结果:
三种注入的优缺点分析
- 属性注入
优点:简洁方便(大部分情况下都用这种注入方式)
缺点:
① 只能用于 IoC 容器
② 不能注入被 final 修饰的属性
- 构造方法注入
优点:
① 可以注入被 final 修饰的属性
② 注入的对象不会被修改
③ 依赖对象在使用前一定会被完全初始化,因为依赖是在类的构造方法中注入的,而构造方法在类加载阶段就会执行
④ 通用性好。因为构造方法是 JDK 支持的, 所以更换任何框架,它都是适用的。也就是说,不加 @Autowired 也可以顺利注入
缺点:注入多个对象时, 构造方法的代码会比较复杂
- setter 注入
优点:在类实例化之后, 重新对该对象进行配置或注入比较方便
缺点:
① 也是不能注入被 final 修饰的属性
② 由于 setter 方法可能会被多次调用,所以注入对象有被修改的风险
对于这两种没法注入被 final 修饰的属性,有两种解决方式:
① 在构造方法中赋值
② 在定义时就进行初始化
@Primary、@Qualifier、@Resource
当同一个类存在多个 bean 时, 使用 @Autowired 就会有问题
public class BeanConfig {
@Bean
public User user1() {
User user = new User();
user.setAge(24);
user.setName("zhangsan");
return user;
}
@Bean
public User user2() {
User user = new User();
user.setAge(20);
user.setName("lisi");
return user;
}
}
@Controller
public class UserController {
@Autowired
private User user;
@Autowired
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public void hello() {
System.out.println("UserController...");
userService.hello();
System.out.println(user);
}
}
public class UserService {
public void hello() {
System.out.println("UserService...");
}
}
运行报错:有多个 Bean,不知道要把哪个注入到 UserController 的 User 对象
可以用小标题那三个关键字来解决上述问题
使用
@Primary 注解,可以指定 Bean 默认的实现
@Primary //指定该 bean 为默认 bean 的实现
@Bean
public User user1() {
User user = new User();
user.setAge(24);
user.setName("zhangsan");
return user;
}
使用
@Qualifier 注解可以指定当前要注入的 bean 对象:在
@Qualifier 的
value 属性中,指定注入的 bean 的名称
注意:
@Qualifier 注解必须配合
@Autowired 使用,不能单独用,
版权归原作者 Script_7 所有, 如有侵权,请联系我们删除。