文章目录
通过注解从spring中储存和获取bean对象是非常简单的一种方法,前面我们已经介绍了如何将
bean
存入
spring
容器中,这里我们将了解如何通过注解将
bean
从
spring
容器中再读取出来。
读取bean对象也叫对象装配、对象注入、依赖注入,就是将获取出的对象放到某个类中,让这个类进行使用。
对象注入:
如果类A需要使用类B的实例,可以直接在类A中创建一个类B的实例,也可以将类B的实例对象从Spring容器中拿出来,像打针一样“注入”类A中,由Spring动态的管理和使用,这就是“注入”。
注解@Autowired.
通过使用注解@Autowired
来进行对象的注入,这个注解是Spring容器配置的一个注解,与其同属容器配置的注解还有:@Required
,@Primary
, @Qualifier
等等.这个注解根据字面意思理解是autowired,自动装配。即将bean对象和需要这个bean的类装配到一起。
用法如下:
属性注入
//属性注入
@Autowired
private UserService userService;
举例:我们将Service类的实例注入到Controller类中进行使用。
创建一个UserService类:
package com.Service;
import com.User.User;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public User findById(int id){
User user=new User();
if(id==1){
user.setName("张三");
user.setAge(18);
user.setId(1);
}else if(id==2){
user.setName("李四");
user.setAge(18);
user.setId(2);
}
return user;
}
}
创建UserController类:
package com.Controller;
import com.User.User;
import com.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
//属性注入
@Autowired
private UserService userService;
public User findById(Integer id){
if(id==null){
return new User();
}
return userService.findById(id);
}
}
创建测试类:
import com.Controller.UserController;
import com.User.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("a.xml");
UserController userController=(UserController) context.getBean("userController",UserController.class);
User user= userController.findById(2);
System.out.println(user);
}
}
输出:
User{
name='李四', age=18, Id=2}
Setter注入
public class UserController {
//设置一个字段
private UserService userService;
//为这个字段生成一个set方法,然后加上注解
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
//调用bean对象的方法进行使用
public User findById(Integer id){
return userService.findById(id);
}
}
构造方法注入
public class UserController3 {
//先生成一个字段
private UserService userService;
//然后生成构造方法,前面加上注解
@Autowired
public UserController3(UserService userService) {
this.userService = userService;
}
}
注意:
- 使用注解获取bean的前提是这个类能被spring扫描到,即类前需要加注解@Controller、@Component、@Service等等几个类似注解中的一个。
- 这三种注入的第一步操作都是先生成一个要注入对象的字段,第一种直接在字段上注解,第二种为这个字段生成一个set方法然后注解,第三种为这个字段生成一个构造方法,然后在方法上注解。使用方式类似,功能相同,第一种更简便。
- 通过构造方法注入时,如果当前类只有一个构造方法,那么@Autowired注解可以被省略,如果有多个构造方法,就不能省略。
三种注入的优缺点
属性/字段注入:
- 优点:简洁、方便
- 缺点:只能用于IOC容器,非IOC容器会出现空指针异常,而且默认是非final的,容易出现循环依赖问题
构造方法注入:
- 优点:通用性强,不受IOC容器的限制,能保证注入的类不为空,在代码中能一眼就能看出当前类需要哪些类才能工作。
- 缺点:多个注入会显得代码非常繁琐,且多个注入不符合单一设计的思想,一旦使用了构造方法注入,那么默认的构造方法就无法使用
Set方法注入:
- 优点:对于循环依赖问题免疫
- 缺点:不能将对象设置为final
注解@Resource.
@Resource中有两个重要的属性:name和type.
spring将name属性解析为bean的名字 ,type属性解析为bean的类型。
进行对象注入也可以通过@Resource实现,使用方法与@Autowired类似:
1.属性注入
public class UserController {
//添加注解在字段上
@Resource
private UserService userService;
public User findUser(Integer id){
return userService.findById(id);
}
}
2.构造方法注入
public class UserController2 {
private UserService userService;
//先创建字段,然后添加注释在构造方法上
@Resource
public void setUserService(UserService userService) {
this.userService = userService;
}
public User findUser(Integer id){
return userService.findById(id);
}
}
注意!!
- @Resource没有构造方法注入
@Resource与@Autowired区别
- 来源不同,@Autowired来自于Spring框架,而@Resource来自于JDK
- 作用范围不同,@Autowired可以进行属性注入,Setter注入,构造器注入;而@Resource只能进行属性注入和Setter注入
- 功能不同,@Resource可以配合更多的属性进行使用,而@Autowired支持的属性比较少,比如@Resource可以配合name属性使用,完成对象的别名注入。
- 注入方式不同,@Autowired是按照byType注入,即按照bean的类型注入,而@Resource是按照byName进行注入的。
注入对象名称问题
当我们把一个对象注入到一个类中的时候,@Autowired和@Resource会尝试着去获取这个对象,首先得先找到这个对象。
在查找这个对象的时候,按照两个标准进行查找,一个是对象名称,另一个是对象类型。
- 先根据名称进行获取,如果获取不到,就会根据类型进行获取,如果也获取不到,就会抛出异常。
- 如果名称不匹配,但是类型匹配,且类型匹配相同的对象有多个,也会抛出异常,无法确定是哪一个。
所有在查找时,我们有多种解决方法:
可以通过@Resource(name=“”)来指定bean:
也可以使用@Qualifier限定符,限定一个bean来进行查找。
@Resource
@Qualifier("user1")
private UserService userService;