阿华代码,不是逆风,就是我疯
你们的点赞收藏是我前进最大的动力!!
希望本文内容能够帮助到你!!
目录
引入
上一篇文章介绍了@Bean注解的使用和扫描路径的配置,本文主要介绍如何将交给Spring管理的Bean对象怎样注入,也就是使用Bean对象
一:DI详解
依赖注入是一个过程,指在IoC容器创建Bean的时候,提供对象这个资源,之前我们学习了@Autowired这个注解,完成依赖注入,即把对象取出来,放到某个类的属性中去。
Spring提供了三种依赖注入的方式
1:属性注入
属性注⼊是使⽤ @Autowired 实现的,将Service类注⼊到Controller类中.
(1)Service类的实现代码如下
java
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void sayHi() {
System.out.println("Hi,UserService");
}
}
(2)Controller 类的实现代码如下:
java
@Controller
public class UserController {
// 注⼊⽅法1: 属性注⼊
@Autowired
private UserService userService;
public void sayHi() {
System.out.println("hi,UserController...");
userService.sayHi();
}
}
(3)获取Controller中的sayHi⽅法:
java
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
// 获取Spring上下⽂对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
// 从Spring上下⽂中获取对象
UserController userController = (UserController) context.getBean("userController");
// 使⽤对象
userController.sayHi();
}
}
运行结果
2:构造方法注入
注意:
如果类只有⼀个构造⽅法,那么@Autowired 注解可以省略;
如果类中有多个构造⽅法, 那么需要添加上@Autowired 来明确指定到底使⽤哪个构造⽅法。
java
@Controller
public class UserController2 {
// 注⼊⽅法2: 构造⽅法
private UserService userService;
@Autowired
public UserController2(UserService userService) {
this.userService = userService;
}
public void sayHi() {
System.out.println("hi,UserController2...");
userService.sayHi();
}
}
3:Setter注入
注意:Setter 注⼊和属性的Setter⽅法实现类似,只不过在设置set⽅法的时候需要加上@Autowired 注解
java
@Controller
public class UserController3 {
// 注⼊⽅法3: Setter⽅法注⼊
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public void sayHi() {
System.out.println("hi,UserController3...");
userService.sayHi();
}
}
二:三种注入方式的优缺点分析
1:属性注入的优缺点
(1)优点
简洁,使用方便
(2)缺点
①只能用于IoC容器,非IoC容器使用会报空指针异常
②不能注入一个Final修饰的属性
解释:@Autowired底层是基于反射来注入的,它需要一个无参的构造方法或setter方法来完成注入操作,final
属性必须在声明时或构造方法中初始化,不能通过 setter 或反射修改。
举例以下这段代码
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyService {
@Autowired
private final SomeDependency someDependency; // 使用了 final 修饰
public MyService() {
// 默认构造方法
}
}
运行会抛出以下异常------Bean对象创建异常,不能注入,嵌套异常
java
Caused by: org.springframework.beans.factory.BeanCreationException:
Could not autowire field: final SomeDependency;
nested exception is java.lang.IllegalArgumentException:
Can not set final field
2:构造函数注入的优缺点
(Spring4.X推荐)
(1)优点
①可以注入final修饰的属性
②注入的对象不会被修改
③依赖对象在使用前一定会被完全初始化
④通用性好,构造方法是JDK支持的,所以更换其它任何框架,都是适用的
举例注入final修饰的属性
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyService {
private final SomeDependency someDependency; // 使用 final 修饰
// 构造函数注入
@Autowired
public MyService(SomeDependency someDependency) {
this.someDependency = someDependency;
}
}
(2)缺点
注入多个对象,代码会比较繁琐
3:Setter方法注入的优缺点
(1)优点
①在类实例之后,还可以重新对该对象进⾏配置或者注⼊
(2)缺点
①不能注入一个Final修饰的属性
②如果setter方法被多次调用的话,注入对象就有被修改的风险
总结:三种注入依赖的方式中,构造方式最为推荐,但是现实开发中,我们程序员基本首选都是@Autowired哈哈,你猜为啥~~~
三:类中Bean有多个时,指定默认Bean
【Spring】方法注解@Bean,配置类扫描路径-CSDN博客
在这篇文章中,我们对于一个类中存在多个Bean对象时,提出的解决方式是,根据名称获取Bean对象,(名称默认是方法名)如果名称太拐杖,我们还可以进行重命名。但是这种方式明显比较复杂,下面我们介绍三种解决方式
0:引入问题代码供参考
java
@Component
public class BeanConfig {
@Bean("u1")
public User user1() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
@Bean
public User user2() {
User user = new User();
user.setName("lisi");
user.setAge(19);
return user;
}
}
java
@Controller
public class UserController {
@Autowired
private UserService userService;
// 注⼊user
@Autowired
private User user;
public void sayHi() {
System.out.println("hi,UserController...");
userService.sayHi();
System.out.println(user);
}
}
1:@Primary
使⽤@Primary注解:当存在多个相同类型的Bean注⼊时,加上@Primary注解,来确定默认的实现
java
@Component
public class BeanConfig {
@Primary // 指定该bean为默认bean的实现
@Bean("u1")
public User user1() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
2:@Qualifier
指定当前要注入的Bean对象,在这个注解的value属性中,指定要注入的Bean的名称
注意:@Qualifier不能单独使用,必须搭配@Autowired使用
java
@Controller
public class UserController {
@Qualifier("user2") // 指定bean名称
@Autowired
private User user;
public void sayHi() {
System.out.println("hi,UserController...");
System.out.println(user);
}
}
3:@Resource
这个注解是JDK提供的,对@Resource中name属性进行赋值,指定Bean的名称进行注入,
java
@Controller
public class UserController {
@Resource(name = "user2")
private User user;
public void sayHi() {
System.out.println("hi,UserController...");
System.out.println(user);
}
}
四:@Autowired和@Resource有什么区别
1:@Autowired是Spring框架提供的注解,@Resource是JDK提供的注解
2:@Autowired默认是按照类型注入,而@Resource是按照名称注入,可以支持更多的参数设置,比如name ,type。例如以下这段代码
这也是面试常考的一个点
java
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class MyService {
@Resource(name = "specificDependency", type = SomeDependency.class)
private SomeDependency someDependency;
public void performTask() {
someDependency.execute();
}
}
@Component("specificDependency")
class SomeDependency {
public void execute() {
System.out.println("Dependency executed!");
}
}