依赖注入是⼀个过程,是指IoC容器在创建Bean时,去提供运⾏时所依赖的资源,⽽资源指的就是对象. 在上⾯程序案例中,我们使⽤了 @Autowired 这个注解,完成了依赖注⼊的操作. 简单来说,就是把对象取出来放到某个类的属性中。
关于依赖注⼊,Spring也给我们提供了三种⽅式:
1. 属性注入(FieldInjection)
2. 构造⽅法注入(ConstructorInjection)
3. Setter 注入(SetterInjection)
4.1 属性注入
属性注⼊是使⽤ @Autowired 实现的,将Service类注⼊到Controller类中.
Service 类的实现代码如下:
@Service
public class UserService {
public void sayHi() {
System.out.println("Hi,UserService");
}
}
Controller 类的实现代码如下:
@Controller
public class UserController {
@Autowired
private UserService userService;
public void sayHi(){
System.out.println("hi,UserController...");
userService.sayHi();
}
}
获取Controller中的sayHi方法:
public class DemoApplication {
public static void main(String[] args) {
//获取Spring上下文对象
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
//从Spring上下文中获取对象
UserController userController = (UserController) context.getBean("userController");
//使用对象
userController.sayHi();
}
}
运行结果:
去掉@Autowired,再运行⼀下程序看看结果:
4.2 构造方法注入
构造方法注入是在类的构造方法中实现注入,如下代码所示:
@Controller
public class UserController {
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
public void sayHi() {
System.out.println("hi,UserController...");
userService.sayHi();
}
}
注意事项:如果类只有⼀个构造方法,那么@Autowired 注解可以省略;如果类中有多个构造方法, 那么需要添加上@Autowired 来明确指定到底使用哪个构造方法。
4.3 Setter 注入
Setter 注入和属性的Setter方法实现类似,只不过在设置set方法的时候需要加上@Autowired 注 解,如下代码所示例:
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService service) {
this.userService = service;
}
public void sayHi() {
System.out.println("hi,UserController...");
userService.sayHi();
}
}
4.4 三种注入优缺点分析
优点 | 缺点 | |
属性注入 | 简洁,使用方便 | 1、只能⽤于IoC容器,如果是⾮IoC容器不可⽤,并且只有在使⽤的时候才会出现NPE(空指 针异常) 2、不能注⼊⼀个Final修饰的属性 |
构造函数注入(Spring4.X推荐) | 1、可以注⼊final修饰的属性 2、注⼊的对象不会被修改 3、 依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法 是在类加载阶段就会执⾏的⽅法. 4、 通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的 | 注⼊多个对象时,代码会⽐较繁琐 |
Setter注入(Spring3.X推荐) | 方便在类实例之后,重新对该对象进⾏配置或者注⼊ | 1、不能注⼊⼀个Final修饰的属性 2、注⼊对象可能会被改变,因为setter⽅法可能会被多次调⽤,就有被修改的⻛险 |
4.5 @Autowired存在问题
当同⼀类型存在多个bean时,使⽤@Autowired会存在问题
@Component
public class BeanConfig {
@Bean("u1")
public UserInfo user1() {
UserInfo userInfo = new UserInfo();
userInfo.setName("张三");
userInfo.setAge(18);
return userInfo;
}
@Bean
public UserInfo user2() {
UserInfo userInfo = new UserInfo();
userInfo.setName("李四");
userInfo.setAge(20);
return userInfo;
}
}
@Controller
public class UserController {
@Autowired
UserService userService;
@Autowired
UserInfo userInfo;
public void sayHi() {
System.out.println("hi,UserController...");
userService.sayHi();
}
}
编译时出现报错
报错的原因是,非唯一的Bean对象。
Spring提供了以下几种注解的解决方案:
• @Primary
• @Qualifier
• @Resource
使用@Primary注解:当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现.
@Component
public class BeanConfig {
@Primary //指定该bean为默认的bean的实现
@Bean("u1")
public UserInfo user1() {
UserInfo userInfo = new UserInfo();
userInfo.setName("张三");
userInfo.setAge(18);
return userInfo;
}
@Bean("u2")
public UserInfo user2() {
UserInfo userInfo = new UserInfo();
userInfo.setName("李四");
userInfo.setAge(20);
return userInfo;
}
}
使用@Qualifier注解:指定当前要注⼊的bean对象。在@Qualifier的value属性中,指定注入的bean 的名称。
@Qualifier注解不能单独使用,必须配合@Autowired使用
@Controller
public class UserController {
@Qualifier("u2")
@Autowired
private UserInfo userInfo;
public void sayHi() {
System.out.println("hi,UserController...");
System.out.println(userInfo);
}
}
运行结果:
使用@Resource注解:是按照bean的名称进行注入。通过name属性指定要注⼊的bean的名称。
@Controller
public class UserController {
@Resource(name="u2")
private UserInfo userInfo;
public void sayHi() {
System.out.println("hi,UserController...");
System.out.println(userInfo);
}
}
运行结果:
@Autowird与@Resource的区别
1、@Autowired是spring框架提供的注解,而@Resource是JDK提供的注解
2、@Autowired默认是按照类型注入,而@Resource是按照名称注入.相比于@Autowired来说 @Resource支持更多的参数设置,例如name设置,根据名称获取Bean.
Autowired装配顺序