目录
之前存储 Bean 时,需要在 spring-config 中添加⼀⾏ bean 注册内容,比较麻烦
简介
在 Spring 中想要更简单的存储和读取对象的核心是使用注解。
- 使用类注解(5大类注解)
- @Controller 控制器:验证用户请求的数据的正确性(安保系统)
- @Service 服务:编排和调度具体的执行方法的(客服)
- @Repository 仓库 服务持久层:和数据库交互(执行者)= DAO层(Data Access Object)数据访问层,Repository是DAO中的一种实现。
- @Component 组件: (工具类)
- @Configuration 配置项:存项目当中的一些配置的。
- 使用方法注解 @Bean
前置工作:配置扫描路径
在 spring-config.xml 添加如下配置
<?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="com.bit.service"></content:component-scan>
</beans>
只扫描配置的com.bit.service
路径下的五大类注解。
Spring设计理念:约定大于配置
类注解
@Controller 控制器
控制器:验证用户请求的数据的正确性(安保系统)
@Service 服务
服务:编排和调度具体的执行方法的(客服)
@Repository 持久层
仓库 服务持久层:和数据库交互(执行者)= DAO层(Data Access Object)数据访问层,Repository是DAO中的一种实现。
@Component
组件: (工具类)
@Configuration
配置项:存项目当中的一些配置的。
读取bean
bean命名规则
bean名称使用正常单词,默认使用原类名的首字母小写,可以读取到相应的bean
bean不正常,前两个字母都大写:使用原类名,读取相应bean
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
SController sController = context.getBean("SController", SController.class);
sController.sayHi();
}
public static void main1(String[] args) {
//1.得到spring对象
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//2.得到bean对象
StudentController studentController = context.getBean("studentController", StudentController.class);
//bean名称使用正常单词,使用原类名的首字母小写,可以读取到相应的bean
//bean不正常,前两个字母都大写:使用原类名,读取相应bean
//3.使用bean对象
studentController.sayHi();
}
component-scan能否和bean标签一起使用?
可以。
bean的用法虽然麻烦,但是它可以针对component-scan做一个补充。
比如有些类确实放在component-scan 配置的类下不合适,但又需要将他存储到spring当中,这时就使用bean添加。
五大类注解可以加到不在component-scan的包中使用吗
不可以。
在component-scan下,但是没加五大类注解可以读取bean吗
不可以。一样不能将当前对象存储到spring
在component-scan下的所有子包下的类,只要加了五大类注解,同样能存储到spring中。
当在component-scan下的不同包下,类名相同。
直接的调用,在new ClassPathXmlApplicationContext这一步就会报错。
解决方案
- 修改类名【推荐】
- 添加value。value相当于别名:显示指定名称。
package com.java.demo.controller.bit;
import org.springframework.stereotype.Controller;
@Controller(value = "UserController2")
//value相当于别名:显示指定名称。
public class UserController {
public void sayHi() {
System.out.println("do com java demo controller bit - User Controller sayHi");
}
}
package com.java.demo;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
public void sayHi() {
System.out.println("do com java demo User Controller sayHi");
}
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
UserController userController = context.getBean("userController", UserController.class);
userController.sayHi();
//UserController2 是注解中value的值
com.java.demo.controller.bit.UserController userController2 = context.getBean("UserController2", com.java.demo.controller.bit.UserController.class);
userController2.sayHi();
}
五大类注解的关系
@Controller / @Service / @Repository / @Configuration 都是@Component的子类,都是针对于@Component的扩展。
为什么需要五大类注解
Java 标准分层(至少3层):
- 控制层
- 服务层
- 数据持久层
五大类注解就是根据分层的需求进行创建的。
需要五大注解的原因:让程序员看到注解之后知道当前类的作用。
阿里巴巴标准分层:
方法注解Bean
使用Bean注解时,要求当前的方法必须有返回值,因为bean注解是将当前方法的返回值存到spring当中的。
Bean注解在使用的时候,要配合五大类注解,才能将方法返回的对象存到spring当中。【为spring性能设计所规定的策略】
Bean的命名规则:默认,@Bean存储的对象的名称 = 方法名
@Bean(name = "u1")
/ @Bean(value = "u1")
对bean进行重命名,可以有多个别名,数组表示。@Bean(name = {"user1", "u1"})
@Component
public class UserBeans {
@Bean(name = "u1")
public User user1() {
User user = new User();
user.setUid(1);
user.setUsername("ss");
user.setPassword("123");
user.setAge(12);
return user;
}
}
@Component
public class UserBeans {
@Bean(name = {
"user1", "u1"})
public User user1() {
User user = new User();
user.setUid(1);
user.setUsername("ss");
user.setPassword("123");
user.setAge(12);
return user;
}
}
Q:当bean注解使用了重命名后,默认的方法名,是否还可以继续获取该对象呢?
A:不行。
spring容器中允许
阿里巴巴Java开发手册
分层领域模型规约:
• DO(Data Object):此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
• DTO(Data Transfer Object):数据传输对象,Service 或 Manager 向外传输的对象。
• BO(Business Object):业务对象,可以由 Service 层输出的封装业务逻辑的对象。
• Query:数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止使用 Map 类
来传输。
• VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。
/
实体类的命名规则:
基本对象(和数据库中的一张表):表名:Userinfo 代码名:Userinfo / UserinfoEntity / UserinfoDO
扩展对象:UserinfoVO / UserinfoOtherVO / Userinfo…VO / …
总结:将对象存储到spring容器:
- 在spring配置文件中
<bean id="" class="com.java."></bean>
- 通过注解存储bean
- 配置了扫描路径,只有扫描路径下的包才有可能将bean存储到spring
- 加了五大类注解或@Bean方法注解
获取Bean对象(对象装配)
获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注⼊。
对象装配(对象注入):更加简单的读取bean(从spring容器中读取某个对象,放到当前类里)
对象装配(对象注入)的实现方法以下 3 种:
- 属性注入
- Setter 注入
- 构造方法注入
属性注入
属性注⼊使⽤ @Autowired
实现
@Controller
public class UserController {
@Autowired //注入对象(更加简单的从spring当中读取对象)
private UserService userService;
public void sayHi() {
System.out.println("do com java demo User Controller sayHi");
userService.sayHi();
}
}
优点:简单
缺点:
-
无法实现final修饰的变量注入
-
兼容性不好,只适用于IoC容器
-
风险:因为写法简单,所以违背 单一设计原则 的概率更大。
Setter注入
@Controller
public class UserController {
//setter注入
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public void sayHi() {
System.out.println("do com java demo User Controller sayHi");
userService.sayHi();
}
}
优点:符合单一设计原则,每次都只传递一个对象
缺点:
- 不能注入不可变对象(finally对象)
- 使用setter注入的对象可能会被修改。set方法可以在任意的地方调用设置。
构造方法注入【官方推荐】
@Controller
public class UserController {
//构造方法注入
private UserService userService;
@Autowired //可以不写
public UserController(UserService userService) {
this.userService = userService;
}
public void sayHi() {
System.out.println("do com java demo User Controller sayHi");
userService.sayHi();
}
}
特点:如果当前类中只有一个构造方法的话,那么@Autowired
注解可以省略
优点:
- 可以注入一个不可变的对象(使用finally修饰的对象)
- 注入的对象不会被改变(构造方法只能执行一次)
- 构造方法注入,可以保证注入对象完全被初始化
- 通用性更好
缺点:
为什么构造方法可以注入一个不可变的对象,而属性注入和setter注入不行?
在Java的规定中,被finally修饰的对象,必须满足两个条件中的任意一个
1.finally修饰的对象,要么在创建的时候直接赋值
2.finally修饰的对象,要么在构造方法中赋值
@Resource:另一种注入关键字
@Autowired 和 @Resource 的区别
- 出身不同:@Autowired 来自于 Spring,而 @Resource 来自于 JDK 的注解;
- 使用时设置的参数不同:相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如
name 设置,根据名称获取 Bean。 - @Autowired 可用于 Setter 注入、构造函数注入和属性注入,而 @Resource 只能用于 Setter 注
入和属性注入,不能用于构造函数注入。 - 查找bean的方式不同。在spring容器中查找bean有两种方式 1. 根据类型查找;2. 根据名称查找。
- @Autowired:先根据类型查找(byType),再根据名称查找(byName)
- @Resource:先根据名称去查,再根据类型去查
@Controller
public class UserController2 {
// @Autowired,在拿值的时候,名字必须和bean里面一样
@Autowired
private User user1;
public void sayHi() {
System.out.println("do com java demo Controller UserController2 sayHi");
System.out.println(user1.getUsername());
}
}
@Controller
public class UserController2 {
@Resource(name = "user1") // 在容器里面拿值的时候,找名叫user1的bean,
private User user;
public void sayHi() {
System.out.println("do com java demo Controller UserController2 sayHi");
System.out.println(user.getUsername());
}
}
@Controller
public class UserController2 {
//使用 @Qualifier + @Qualifier(value = "user1") 实现和@Resource(name = "user1")一样的功能
@Autowired
@Qualifier(value = "user1")
private User user;
public void sayHi() {
System.out.println("do com java demo Controller UserController2 sayHi");
System.out.println(user.getUsername());
}
}