Spring更简单保存和获取bean对象的方法
- 前置准备
- 将bean对象更为简单地保存到Spring容器中(使用注解)
- 【使用类注解】 (是写在类前的)
- 为什么要这么多类注解?
- 类注解之间的关系
- 使用类注解 Bean 命名规则
- 使用方法注解(@Bean)不常用
- 使用@bean方法注解将对象保存到Spring容器中,该bean对象的命名规则
- 获取Spring容器的bean对象
- 属性注入
- 属性注入的有缺点
- setter注入
- Setter注入的优缺点
- 构造方法注入
- 构造方法注入的注意事项
- 构造方法注入的有缺点
- @Resource:另⼀种注⼊关键字
- @Resource注解实现属性注入
- @Resource注解实现setter注入
- @Resource注解无法实现构造方法注入
- @Resource注解和 @Autowired注解的比较
- 同⼀类型多个 @Bean 报错问题
- 解决方案
- 【方法一】我们将变量名设计的跟我们要找的bean对象的id名相同就行。(这个方法不提倡使用,不太好)
- 【方法二】使用@Resource注解的name参数或者type参数
- 使用 @Autowired注解和 @Qualifier注解
我们介绍了通过配置spring.xml配置文件的方式来保存和获取bean对象,但是,通过配置文件的方式来保存和获取bean对象并不方便和简洁。所以,我在介绍一个更加简单和方便的方法—>通过注解的方式来保存和获取bean对象
前置准备
我们还是需要创建一个spring-config.xml配置文件,并且还需要添加一个标签来配置Spring的注解扫描路径
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:content="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<content:component-scan base-package="扫描的根目录"></content:component-scan>
<!-- 扫描注解 -->
</beans>
将bean对象更为简单地保存到Spring容器中(使用注解)
【使用类注解】 (是写在类前的)
<1>@Controller【控制器】验证前端传递的参数【安全检查】
<2>@Service【服务】服务调用的编排和汇总
<3>@Repository【仓库】直接操作数据库
<4>@Component【组件】通用化的工具类
<5>@Configuration【配置】项目的所有配置
使用方式也很简单,只要将注解写在要给Spring管理的类前就行了(注意:要配置好扫描路径,要在扫描路劲里)
示例截图:
为什么要这么多类注解?
就是让程序员看到类注解之后,就能直接了解当前类
的⽤途,⽐如:
@Controller:表示的是业务逻辑层;
@Service:服务层;
@Repository:持久层;
@Configuration:配置层
程序的⼯程分层,调⽤流程如下:
类注解之间的关系
查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现,他们都有使用用@Component,
他们都是基于@Component实现的。
使用类注解 Bean 命名规则
我们在使用五个类注解让对象交给Spring管理的时候,我们可以自己给对象命名,或者使用bean的默认名字
【方式一】自己给对象命名,以@Controller为例
@Controller(“我们自己取的名字”)
【方式二】使用默认名字
规则:
一般情况:类名的第一个字母为大写,第二个字母为小写,bean的id(名字)是该类的类名,但是类名的第一个字母要改为小写
特殊情况:类名的第一个字母和第二个字母都为大小,bean的id是该类的类名.
如果类名是一个字母,不管大小写,bean的id都是类名,并且第一个字母小写
使用方法注解(@Bean)不常用
【使用方法注解】 (是写在方法前的)
@Bean
@Bean 的作用:将方法返回的对象保存到Spring的容器中
注意:
- @Bean不能单独使用,要搭配5大类注解使用
- @bean方法注解只能用在无参的方法(Spring初始化存储时,无法提供相应的参数)
使用@bean方法注解将对象保存到Spring容器中,该bean对象的命名规则
【使用默认的命名规则】
以方法名为该bean对象的id名
【程序员可以直接设置bean对象的id名】
注意:如果程序员自己设置bean对象的id名,则bean对象默认的id名也就不能使用
<1>
@bean(name="id名字")
<2>
@Bean(value = "id名字")
<3>
@Bean("id名字")
<4>一个bean对象可以设置多个id名称
@Bean(name = {"id名字","id名字"....})
@Bean(value = {"id名字","id名字"....})
获取Spring容器的bean对象
获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注⼊,有时候也叫依赖注入
对象注入的方式有三种:
- 属性注入(Field Injection)
- Setter注入(Setter Injection)
- 构造方法注入(Constructor Injection)
属性注入
属性注⼊是使⽤ @Autowired 实现的,在要注入的属性对象前加上@Autowired就行。
注入的前提是:要注入的对象要保存在Spring容器中
@Component
public class StudentController {
@Autowired
private Student student;
public void doStudentController() {
System.out.println("do StudentController");
student.doStudent();
}
}
属性注入的有缺点
优点:属性注入最大的优点就是实现简单、使用简单,只需要给变量上添加一个注解(@Autowired)
缺点:
- 功能性问题:不能注入一个不可变的对象(final修饰的对象)
- 通用性问题:只能适应于 IoC 容器
- 设计原则问题:更容易违背单一设计原则
setter注入
在要依赖注入的类中写一个set方法,在set方法前加上@Autowired注解就行
Setter注入的优缺点
优点:符合单一设计的有原则(一个setter注入对应一个对象)
缺点
-
不能注入一个不可变的对象(final修饰的对象)
-
注入对象可被修改(set方法可以被多次调用,所有就有被改的风险)
构造方法注入
写一个构造方法,要依赖哪个对象,就设置哪个类型的形参,然后在构造方法前加一个@Autowired注解就行了。
(前提:注入的对象是保存在Spring容器中)
@Controller
public class UserController01 {
//注入UserController02对象,使用属性注入
private UserController02 userController02;
@Autowired
public UserController01(UserController02 userController02) {
this.userController02 = userController02;
}
public void doUserController01() {
System.out.println("user Controller01.");
System.out.println();
userController02.doUserController02();
}
}
构造方法注入的注意事项
<1>使用构造方法注入时,如果构造方法只有一个,则@Autowired注解可以不写,如果有多个构造方法,则@Autowired不能不写。
只有一个构造方法,@Autowired可以不写的情况:
@Controller
public class UserController01 {
//注入UserController02对象,使用属性注入
private UserController02 userController02;
// @Autowired
public UserController01(UserController02 userController02) {
this.userController02 = userController02;
}
public void doUserController01() {
System.out.println("user Controller01.");
System.out.println();
userController02.doUserController02();
}
}
<2>有多个构造方法的情况:
- 我们从Spring获取的bean对象会使用添加了 @Autowired注解的构造方法进行创建和对象注入
- @Autowired注解只能使用在一个构造方法前面,如果使用在多个构造方法前面,则我们在获取Spring上下文对象的时候会有错误。(非常好理解:我们在创建对象的时候只能使用一个构造方法,类比过来是一样的)
- 使用构造方法注入的时候,构造方法里面的参数必须要保存在Spring容器中才行,要不然在获取Spring上下文对象的时候会报错
- 我们使用构造方法注入的时候,如果重载了多个构造方法,但是,不选择一个构造方法添加@Autowired注解,这样在获取Spring上下文对象的时候,依然会保存,Spring在获取该对象的时候,它不知道要使用哪个构造方法
- 我们在使用构造方法注入的时候,重载了多个构造方法,其中有一个构造方法什么值都不传,可以以不添加@Autowired注解,但是,我们在获取Spring上下文的时候,创建bean对象时就会默认调用没有参数的构造方法
构造方法注入的有缺点
优点:
- 可以注入final修饰的对象
- 注入的对象不会被修改
- 依赖的对象在使用前会被完全初始化
- 通用性更好
@Resource:另⼀种注⼊关键字
之前我们在实现 属性注入、setter注入和构造方法注入 是 使用 @Autowired注解 来实现的。@Autowired注解是Spring框架提供的注解。而@Resource则是java自己提供的注解。
@Resource注解实现属性注入
用法和@Autowired注解是一样的
@Controller
public class UserController01 {
@Resource
private UserController02 userController02;
public void doUserController01() {
System.out.println("user Controller01.");
System.out.println();
userController02.doUserController02();
}
}
@Resource注解实现setter注入
用法和@Autowired注解是一样的
@Controller
public class UserController01 {
private UserController02 userController02;
@Resource
public void setUserController02(UserController02 userController02) {
this.userController02 = userController02;
}
public void doUserController01() {
System.out.println("user Controller01.");
System.out.println();
userController02.doUserController02();
}
}
@Resource注解无法实现构造方法注入
我们能很清楚的看到,@Resource注解放到构造方法前就直接报错了
@Resource注解和 @Autowired注解的比较
相同点:
@Resource注解和 @Autowired注解都能实现对象注入
不同点:
-
出身不同:@Resource注解是由java自己提供的,而@Autowired注解是由Spring提供的
-
依赖注入的用法不同: @Autowired注解可以实现属性注入、setter注入和构造方法注入,
而@Resource注解只能实现属性注入和setter注入 ,@Resource注解不能实现构造方法注入
-
支持的参数不同
@Resource注解里面可以设置很多种参数,而@Autowired注解只能设置一种参数
依赖查找的顺序不同
@Autowired注解先查找Spring容器中是否用要依赖类的类型,找到后,如果有多个则在通过比较bean对象的id名称
而@Resource注解先是通过比较bean对象的id名称来进行配对,找到后,如果有多个,则通过类型进行配对
这里需要特别注意一下:这里我们要清楚是哪几个id名称进行比较,一个是我们在Spring容器中找到多个符合的bean对象的id名称 和 我们在创建要注入依赖对象的变量名进行比较
同⼀类型多个 @Bean 报错问题
我们在使用@Bean方法注解或者使用xml配置的方法来将对象保存到Spring容器中的时候,很有可以会出现有比较多类型相同,但是bean对象的id名称不同 的情况。我们在使用注解进行对象注入的时候会比较容易出现一下的异常:
意思就是:找到了几个符合类型的bean对象,但是按bean id名匹配没有成功,所有就报错
解决方案
【方法一】我们将变量名设计的跟我们要找的bean对象的id名相同就行。(这个方法不提倡使用,不太好)
原因:不管@Resource注解和 @Autowired注解在注入对象的时候,都会有按照bean对象的id名来匹配,而我们写的变量名就是用来作比较的bean对象的id名。
【方法二】使用@Resource注解的name参数或者type参数
@Resource注解的name参数就是用来设置要匹配哪个bean对象的id名称
@Resource注解的type参数可以用来设置要注入对象的类型
public class UserController01 {
@Resource(name = "user_2")
private User user;
public void doUserController01() {
System.out.println("user Controller01.");
System.out.println();
System.out.println(user);
}
}
使用 @Autowired注解和 @Qualifier注解
单独使用@Autowired注解是不能解决这个问题的,我们还要在搭配使用 @Qualifier注解来指定查找id名称是什么的bean对象。
@Qualifier注解的作用:用来指定查找id名称是多少的bean对象,@Qualifier注解里面只有一个参数,用来设置用来指定查找id名称
@Controller
public class UserController01 {
@Autowired
@Qualifier(value = "user_3")
private User user;
public void doUserController01() {
System.out.println("user Controller01.");
System.out.println();
System.out.println(user);
}
}
注意:@Qualifier注解要搭配 @Autowired注解使用,自己单独使用没有效果