Spring更简单的存储对象
- 将Bean对象简单存储到Spring容器中
- 使用五大类注解来存储Bean对象
- 使⽤ @Controller 存储 bean 对象
- 使⽤ @Service 存储 bean 对象
- 使⽤ @Repository 存储 bean 对象
- 使⽤ @Component 存储 bean 对象
- 使⽤ @Configuration
- 为什么要有五大类注解
- 五大类注解的关系
- 五大类注解的作用
- 使用五大类注解的注意事项
- 在扫描路径下的所有加了五大类的都可以存储Spring
- 在扫描路径下在必须加入注解才能存储到Spring中
- 五大类注解必须在扫描路径下才会存储到Spring中
- < Bean> 和 component-scan 能一起使用
- Bean对象命名规则
- ⽅法注解 @Bean 存储Bean 对象
- ⽅法注解要配合类注解使⽤
- 重命名 Bean 对象
- 使用⽅法注解 @Bean 注意事项
- 重命名后原方法名就不能使用了
- 一个类中可以存储多个相同类型的对象
- 在不同类中有相同的@Bean注解的方法
前面我们已经学习了基本的Spring的读取和存储操作了,但是用标签在配置文件中存储bean对象,在操作的过程中会发现有很多Bean对象的时候就会比较复杂,那么我们接下来就要学习更加简单的操作Bean对象的常用方法。
我们想要进行简单的存储和读取我们需要使用注解,本次我们存储对象主要用的就是五大类注解和一个方法注解。
- 五大类注解:@Controller @Service @Repository @Component @Configuration
- 方法注解:@Bean
将Bean对象简单存储到Spring容器中
使用五大类注解来存储Bean对象
我们使用五大类注解之前我们必须要有一些前置工作。前一篇说的maven的创建,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="com.java.beans"></content:component-scan>
</beans>
接下啦我们就可以在beans包内部创建Bean对象了。
使⽤ @Controller 存储 bean 对象
使⽤ @Controller 存储 bean 对象的代码如下
@Controller
public class UserController {
public void sayHello(){
System.out.println("hello world UserController");
}
}
使用启动类来读取Spring容器中的UserController对象,代码如下:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
UserController userController = context.getBean("userController",UserController.class);//获取Bean对象
userController.sayHello();//使用Bean对象
}
}
在这里先用首字母小写来表示Bean对象的名称。具体原因我们在本文章后面会解释
使⽤ @Service 存储 bean 对象
使⽤ @Service 存储 bean 对象的代码如下
@Service
public class UserService {
public void sayHello(){
System.out.println("hello world UserService");
}
}
使用启动类来读取Spring容器中的UserService对象,代码如下:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
UserService userService = context.getBean("userService",UserService.class);//获取Bean对象
userService.sayHello();//使用Bean对象
}
}
使⽤ @Repository 存储 bean 对象
使⽤ @Repository 存储 bean 对象的代码如下
@Repository
public class UserRepository {
public void sayHello(){
System.out.println("hello world UserRepository");
}
}
使用启动类来读取Spring容器中的UserRepository对象,代码如下:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
UserRepository userRepository = context.getBean("userRepository",UserRepository.class);//获取Bean对象
userRepository.sayHello();//使用Bean对象
}
}
使⽤ @Component 存储 bean 对象
使⽤ @Componen 存储 bean 对象的代码如下
@Repository
public class UserRepository {
public void sayHello(){
System.out.println("hello world UserRepository");
}
}
使用启动类来读取Spring容器中的UserComponent对象,代码如下:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
UserComponent userComponent = context.getBean("userComponent",UserComponent.class);//获取Bean对象
userComponent.sayHello();//使用Bean对象
}
}
使⽤ @Configuration
存储 bean 对象使⽤ @Configuration 存储 bean 对象的代码如下
@Configuration
public class UserConfiguration {
public void sayHello(){
System.out.println("hello world UserConfiguration");
}
}
使用启动类来读取Spring容器中的UserConfiguration对象,代码如下:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
UserConfiguration userConfiguration = context.getBean("userConfiguration",UserConfiguration.class);//获取Bean对象
userConfiguration.sayHello();//使用Bean对象
}
}
使用五大类注解存储的Bean对象,通过启动类获取获取并使用五个都是一模一样
那么我们会有一个疑问五大类注解明明作用没啥区别呀,为啥会有五大类注解呢?
我们针对这个问题就要了解五大类注解的区别和联系
为什么要有五大类注解
五大类注解的关系
我们要了解五大类注解的关系最直接的办法就是看他们的源码:
查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:这四个类注解中定义的时候,都有 @Component注解。这种关系相当于继承关系,这四个类相当于 @Component的一个子类,在拥有@Component的基本功能外有扩展了一些功能。
五大类注解的作用
五大类注解他们相同的功能是将Bean对象存储到Spring容器中。我们了解他们的作用之前我们先看一下Java程序的⼯程分层
工程分层前端不能直接和数据库交互,前端和后端交互,后端和数据库进行交互。前端的数据传到后端,我们并不能直接将进行处理数据进行操作数据库,必须先由控制器来验证数据的正确性错误的话就不进行下一步数据的传送了,如果数据正确,我们就把数据交给服务层,控制器就相当于后端的一个安保系统。服务层不是直接操作数据库的是编排和调度具体的执行方法的,有的主句不一定是要操作一个数据库,也有可能多个,我们的服务层就相当于一个客服中心,你要办理一个业务客服中心不是直接给你处理问题的,他是负责分析你的需求,规划你的问题需要有谁来处理。服务层就把数据传给了数据持久层。数据持久层也叫做数据访问层,数据访问层是和数据库一对一的,是直接操作数据库的。
我们把控制层的类用@Controller注解,服务层的类用@Service来进行注解,数据持久层的类用@Repository来进行注解。当然有的类比如工具类和配置项类放到三层的哪里都不合适所以我们又将工具类用@Component来注解,配置项用@Configuration来注解
类注解分为五个的作用就是让程序员看到注解后知道当前类的的作用,一看到@Controller注解就知道该类是和前端进行交互的,一看到@Repository就知道该类是和数据库进行交互的。代码不仅是给计算机看的也是给程序员看的,一个好的代码是让长时间没有接触过项目的自己和其他程序员更容易看懂,注解的分类和注释有着相同的作用,就是为了让代码更易读。其他程序员更好接手这个项目。
- @Controller 控制器:验证用户的请求十五数据正确性(安保系统)
- @Service 服务:编排和调度具体的执行方法(服务中心)
- @Repository 持久层:和数据库交互;(执行者) = DAO(Data Access Obiect)数据访问层
- @Component 组件 : (工具类)
- @Configuration 配置项 : (项目中的一些配置)
使用五大类注解的注意事项
在扫描路径下的所有加了五大类的都可以存储Spring
在扫描路径下的两重包内部的一个类
@Service
public class StudentService {
public void sayHello(){
System.out.println("hello world sayHello()");
}
}
启动类获取并使用bean对象:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
StudentService studentService = context.getBean("studentService",StudentService.class);//获取Bean对象
studentService.sayHello();//使用Bean对象
}
}
在扫描路径下在必须加入注解才能存储到Spring中
将类的注解注释掉:
启动类调用该类就会报错:
五大类注解必须在扫描路径下才会存储到Spring中
在扫描路径外用五大类注解:
@Service
public class TeacherServer {
public void sayHello(){
System.out.println("hello world TeacherServer");
}
}
在启动类中取出Bean对象并使用:
说明五大类注解必须在扫描路径下才能存储到Spring容器中
< Bean> 和 component-scan 能一起使用
在配置文件中加一行<bean>
在启动类中使用Bean对象:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
UserService userService = context.getBean("userService",UserService.class);//获取Bean对象
userService.sayHello();//使用Bean对象
}
}
结果正常输出:
Bean对象命名规则
前面我们都是用的首字母小写,但是也不全是首字母小写,首字母小写是针对第一个字母大写第二个字母小写时候的规则,其他情况下有着其他的规则。
比如我们有第一个字母和第二个字母全是大写的类名。
@Controller
public class SController {
public void sayHello(){
System.out.println("hello world SController");
}
}
我们在启动类中用第一个字母小写的命名规则来看一下是否正确。
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
SController sController = context.getBean("sController",SController.class);//获取Bean对象
sController.sayHello();//使用Bean对象
}
}
最后输出结果报错:
我们正确的命名方式就是名称为类型的原名
这样就会输出正确的结果。
我们为什么会有两种命名规则呢?这个原因还得在源码中去看了:
我们通过源码了解到了Bean对象命名规则,有的人会问如果Bean对象第一个字母小写,那么他的名称是什么呢?这个问题呢其实就是第二条规则,把第一个字母小写就行了。但是你要是第一个字母小写,别说Bean对象的命名规则了,你的领导恐怕会批评你的命名不规范。
在查看源码的时候我们就会发现我们这个源码并不是Spring提供的,是在rt.jar包中的,而rt.jar包是在JDK当中。该命名规则是JDK自带的。
命名规则:
- 默认情况下,首字母小写
- 如果类名首字母和第二个字母都为大写的情况下,Bean名称为原类名
⽅法注解 @Bean 存储Bean 对象
类注解是添加到某个类上的,⽽⽅法注解是放到某个⽅法上的。
我们想要使用@Bean 存储Bean 对象,我们先做准备工作创建一个User类,该类是属于 @Repository数据持久层,是一个基本对象,是对应数据库的一张表,命名规则可有三类:数据库名/数据库名 + Entity/ 数据库名 + DO
public class User {
private Integer uid;
private String username;
private String password;
private Integer age;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
⽅法注解要配合类注解使⽤
使用⽅法注解 @Bean 存储Bean 对象到Spring容器中:
下列代码都是为了介绍@Bean注解的使用。不要纠结为啥Spring容器还要new对象。
public class UserBeans {
@Bean
public User user(){
User user = new User();
user.setUid(1);
user.setAge(18);
user.setUsername("张三");
user.setPassword("123456");
return user;
}
}
Bean对象的名称为类名
使用启类获取Bean对象:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
User user = context.getBean("user",User.class);
System.out.println(user.getUsername());
}
}
这样存储不进Spring容器中。原因是配置文件扫描不到该@Bean注解,我们得和类注解配合使用:
@Controller
public class UserBeans {
@Bean
public User user(){
User user = new User();
user.setUid(1);
user.setAge(18);
user.setUsername("张三");
user.setPassword("123456");
return user;
}
}
使用启类获取Bean对象的结果:
我们在使用@Bean注解的时候,必须在⽅法注解要配合类注解使⽤,我们若不使用类注解的话,直接使用方法注解的话,这样使用启动类调用会报错的。原因是为了效率,我们如果所有的类都进行扫描的话效率会很低,如果只调用五大类注解过的类,扫描效率会更高一些。
重命名 Bean 对象
可以通过设置 name 属性给 Bean 对象进⾏重命名操作,如下代码所示:
@Controller
public class UserBeans {
@Bean(name = "user1")
public User user(){
User user = new User();
user.setUid(1);
user.setAge(18);
user.setUsername("张三");
user.setPassword("123456");
return user;
}
}
在启动类中重命名的名称获取Bean对象
@Controller
public class UserBeans {
@Bean(name = "user1")
public User user(){
User user = new User();
user.setUid(1);
user.setAge(18);
user.setUsername("张三");
user.setPassword("123456");
return user;
}
}
这个重命名的 name 其实是⼀个数组,⼀个 bean 可以有多个名字:
@Bean(name = {"user1","user2"})
public User user(){
User user = new User();
user.setUid(1);
user.setAge(18);
user.setUsername("张三");
user.setPassword("123456");
return user;
}
并且 name={ } 可以省略,如下代码所示:
@Controller
public class UserBeans {
@Bean({"user1","user2"})
public User user(){
User user = new User();
user.setUid(1);
user.setAge(18);
user.setUsername("张三");
user.setPassword("123456");
return user;
}
}
除了用name也可以用value
通过源码可得知这name和value是一样的。
使用⽅法注解 @Bean 注意事项
重命名后原方法名就不能使用了
@Controller
public class UserBeans {
@Bean(value = {"user1","user2"})
public User user(){
User user = new User();
user.setUid(1);
user.setAge(18);
user.setUsername("张三");
user.setPassword("123456");
return user;
}
}
启动类:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
User user = context.getBean("user",User.class);
System.out.println(user.getUsername());
}
}
这个就好像一个宠物猫,你没有起名字的时候可以叫猫的名字,起了名字以后就要叫猫的名字了。
一个类中可以存储多个相同类型的对象
@Controller
public class UserBeans {
@Bean(value = {"user1","user2"})
public User user(){
User user = new User();
user.setUid(1);
user.setAge(18);
user.setUsername("张三");
user.setPassword("123456");
return user;
}
@Bean
public User user3(){
User user = new User();
user.setUid(2);
user.setAge(20);
user.setUsername("李四");
user.setPassword("123456");
return user;
}
}
在启动类中调用:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
User user = context.getBean("user1",User.class);
System.out.println(user.getUsername());
User user3 = context.getBean("user3",User.class);
System.out.println(user3.getUsername());
}
}
在不同类中有相同的@Bean注解的方法
我们再创建一个类是和UserBeans存储的一样的@Bean注解的方法
@Controller
public class UserBeans2 {
@Bean
public User user3(){
User user = new User();
user.setUid(3);
user.setAge(20);
user.setUsername("王五");
user.setPassword("123456");
return user;
}
}
在启动类中调用:
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");//获取spring上下文
User user3 = context.getBean("user3",User.class);
System.out.println(user3.getUsername());
}
}
会成功使用Bean对象,使用的原则是后注入的把先注入的给覆盖掉。我们可以用**@Order()注解来控制注入顺序**
输出结果:
调整注入顺序:
输出结果:
经过上述讲解,已经了解了Spring更简单的存储对象,下一节我们将会介绍Spring更简单的读取对象