@TOC
获取 Bean 对象(对象装配)
获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注⼊。
对象装配(对象注⼊)的实现⽅法以下 3 种:
属性注⼊
构造⽅法注⼊
接下来,我们分别来看。
下⾯我们按照实际开发中的模式,将 Service 类注⼊到 Controller 类中
@Autowired 注解
通过使用注解@Autowired来进行对象的注入,这个注解是Spring容器配置的一个注解,与其同属容器配置的注解还有:@Required,@Primary, @Qualifier 等等.这个注解根据字面意思理解是autowired,自动装配。即将bean对象和需要这个bean的类装配到一起。
1. 属性注入
属性注⼊是使⽤ @Autowired 实现的,将 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}2. Setter 注入
Setter 注⼊和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加上 @Autowired 注解
如下代码所示:
@Controller 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); } }3. 构造方法注入
构造⽅法注⼊是在类的构造⽅法中实现注⼊
如下代码所示:
@Controller public class UserController3 { //先生成一个字段 private UserService userService; //然后生成构造方法,前面加上注解 @Autowired public UserController3(UserService userService) { this.userService = userService; } }注意:
通过构造方法注入时,如果当前类只有一个构造方法,那么@Autowired注解可以被省略,如果有多个构造方法,就不能省略。
三种注入优缺点分析
1.属性注⼊
-
优点 是 简洁,使⽤⽅便
- 缺点 是 只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指针异常)
2.构造⽅法注⼊
- 优点 Spring 推荐的注⼊⽅式。优点是通⽤性,在使⽤之前⼀定能把保证注⼊的类不为空
- 缺点是如果有多个注⼊会显得⽐较臃肿,但出现这种情况你应该考虑⼀下当前类是否符合程序的单⼀职责的设计模式了,在使⽤之前⼀定能把保证注⼊的类不为空。
3.Setter 注入
- 是 Spring 前期版本推荐的注⼊⽅式,
- 优点:对于循环依赖问题免疫
- 缺点:不能将对象设置为final
- 通⽤性不如构造⽅法,所有 Spring 现版本已经推荐使⽤构造⽅法注⼊的⽅式来进⾏类注⼊了。
@Resource 注解
在进⾏类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊
@Resource 来自 JDK,@Autowired 来自 Spring
@Resource中有两个重要的属性:name和type
spring将name属性解析为bean的名字 ,type属性解析为bean的类型
1.属性注入
如下代码所示:
@Controller public class UserController { //添加注解在字段上 @Resource private UserService userService; public User findUser(Integer id){ return userService.findById(id); } }2.Setter 注入
@Controller 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后byName),而@Resource是按照先byName后byType进行注入的
注入对象名称问题
当我们把一个对象注入到一个类中的时候,@Autowired和@Resource会尝试着去获取这个对象,首先得先找到这个对象。
在查找这个对象的时候,按照两个标准进行查找,一个是对象名称,另一个是对象类型
- 先根据名称进行获取,如果获取不到,就会根据类型进行获取,如果也获取不到,就会抛出异常。
- 如果名称不匹配,但是类型匹配,且类型匹配相同的对象有多个,也会抛出异常,无法确定是哪一个。
同⼀类型多个 @Bean 报错
当出现以下多个 Bean,返回同⼀对象类型时程序会报错,如下代码所示:
@Component public class Users { @Bean public User user1() { User user = new User(); user.setId(1); user.setName("Java"); return user; } @Bean public User user2() { User user = new User(); user.setId(2); user.setName("MySQL"); return user; } }在另⼀个类中获取 User 对象,如下代码如下:
@Controller public class UserController4 { // 注⼊ @Resource private User user; public User getUser() { return user; } }以上程序的执⾏结果如下:
报错的原因是,⾮唯⼀的 Bean 对象
同⼀类型多个 Bean 报错处理:
解决同⼀个类型,多个 bean 的解决⽅案有以下两个:
① 使⽤ @Resource(name="XXX")
通过bean的名称注入
@Controller class UserController4 { // 注⼊ 通过bean的名称注入 @Resource(name = "user1") private User user; public User getUser() { return user; } }