使用注解存储对象
之前我们存储Bean时,需要在spring-config 中添加一行 bean注册内容才行,如下图所示:
问题引入:如果想在Spring 中能够更简单的进行对象的存储和读取,该怎么办呢?
问题解答:实现在Spring中更简单地进行对象的存储和读取操作的核心是使用注解来实现。
也就是我们接下来要学习Spring 中的相关注解,来进行存储和读取Bean对象。
1,五大类注解
1.1,类注解介绍及使用
1)类注解使用前置工作
类注解使用时的前置工作为配置扫描路径,这一步至关重要。该步需要在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.java.example"></content:component-scan>
</beans>
如果想成功地将对象存储到Spring 中,这时我们需要配置一下存储对象的扫描包路径。
只有处于被配置的扫描包路径下的所有类对象,添加类注解之后才能被正确的识别并保存到Spring中。
也就是说,即使类对象添加了类注解,但该类对象不处于被配置的扫描包路径下,也是不能被正确的识别并保存到Spring中。
其中标红的一行为注册扫描的包,如下图所示:
2) @Controller(控制存储)
使用 @Controller 存储 bean对象 操作流程代码:
import org.springframework.stereotype.Controller;
@Controller
public class StudentController {
public void sayHi(){
System.out.println("do student controller sayHi()");
}
}
读取Bean对象并使用的总操作流程代码:
import com.java.example.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main1(String[] args) {
//1,获取Spring上下文
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring-config.xml");
//2,得到Bean对象
StudentController studentController =
applicationContext.getBean("studentController",StudentController.class);
//3,使用Bean对象
studentController.sayHi();
}
}
读取Bean对象并使用的总操作流程代码执行结果:
3)@Service(服务存储)
使用 @Service 存储 bean对象 操作流程代码:
import org.springframework.stereotype.Service;
@Service
public class StudentService {
public void sayHi(){
System.out.println("do student service sayHi()");
}
}
读取Bean对象并使用的总操作流程代码:
import com.java.example.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main2(String[] args) {
//1,获取Spring上下文
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring-config.xml");
//2,得到Bean对象
StudentService studentService =
applicationContext.getBean("studentService",StudentService.class);
//3,使用Bean对象
studentService.sayHi();
}
}
读取Bean对象并使用的总操作流程代码执行结果:
4)@Repository(仓库存储)
使用 @Repository 存储 bean对象 操作流程代码:
import org.springframework.stereotype.Repository;
@Repository
public class StudentRepository {
public void sayHi(){
System.out.println("do student repository sayHi()");
}
}
读取Bean对象并使用的总操作流程代码:
import com.java.example.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//1,获取Spring上下文
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring-config.xml");
//2,得到Bean对象
StudentRepository studentRepository =
applicationContext.getBean("studentRepository",StudentRepository.class);
//3,使用Bean对象
studentRepository.sayHi();
}
}
读取Bean对象并使用的总操作流程代码执行结果:
5)@Component(组件存储)
使用 @Component 存储 bean对象 操作流程代码:
import org.springframework.stereotype.Component;
@Component
public class StudentComponent {
public void sayHi(){
System.out.println("do student component sayHi()");
}
}
读取Bean对象并使用的总操作流程代码:
import com.java.example.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main4(String[] args) {
//1,获取Spring上下文
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring-config.xml");
//2,得到Bean对象
StudentComponent studentComponent =
applicationContext.getBean("studentComponent",StudentComponent.class);
//3,使用Bean对象
studentComponent.sayHi();
}
}
读取Bean对象并使用的总操作流程代码执行结果:
6)@Configuration(配置存储)
使用 @Controller 存储 bean对象 操作流程代码:
import org.springframework.context.annotation.Configuration;
@Configuration
public class StudentConfiguration {
public void sayHi(){
System.out.println("do student configuration sayHi()");
}
}
读取Bean对象并使用的总操作流程代码:
import com.java.example.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main5(String[] args) {
//1,获取Spring上下文
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring-config.xml");
//2,得到Bean对象
StudentConfiguration studentConfiguration =
applicationContext.getBean("studentConfiguration",StudentConfiguration.class);
//3,使用Bean对象
studentConfiguration.sayHi();
}
}
读取Bean对象并使用的总操作流程代码执行结果:
思考:配置信息为何不直接写在配置文件里,而要专门使用配置注解呢?
配置文件是用于提供全局性的配置,可以集中管理和调整各种应用程序的属性和行为。 配置文件具有灵活性,可以在部署环境或实际运行时进行修改,而无需重新编译代码。通过配置文件,可以实现对整个应用程序的配置和调整。
配置注解则更多地用于代码层面的配置和定制。 通过在代码中添加特定的注解,可以实现更精确和定制化的配置。配置注解可以用于声明、配置和管理各种类、组件、服务、Bean等,以实现各种不同的行为和功能,以及使得代码更具可维护性和可读性。
总结:配置文件和注解在Spring Boot项目中是相互补充的。配置文件用于整体性的配置外部化,而注解用于在代码层面进行具体的配置和定义。
1.2,类注解存在的原因
这五大类注解的功能:处于被配置的扫描包路径下的所有的类对象,经添加类注解之后就能被正确的识别并保存到Spring 容器中。
既然这五大类注解的功能是⼀样的,为什么需要这么多的类注解呢?
之所以需要这么多的类注解,是因为想起到程序员看到类注解之后,就能直接知道当前类的作用和功能的效果。
- @Controller:表示控制层,用于验证用户参数的正确性,相当于安保系统。
- @Service:表示服务层,用于编排和调度具体执行方法,相当于客服中心。
- @Repository:表示持久层,用于和数据库进行交互操作,相当于执行者。
- @Component:表示组件,用于标识工具类。
- @Configuration:表示配置层,用于标识配置类。
1.3,类注解之间的关系
1)@Controller 底层实现
2)@Service 底层实现
3)@Repository 底层实现
4)@Configuration 底层实现
5)五大类注解之间关系总结
从上述查看@Controller /@Service /@Repository /@Configuration 这些类注解的源代码不难发现:
这些类注解里面都有一个注解@Component,说明它们本身就是属于@Component 的子类。
1.4,类注解Bean命名规则
查看Bean命名规则的源代码方式流程:
1,在搜索框中输入BeanName,点击标记的方法
2,点击标记的方法,就可以查看到对应的命名规则源代码
3,对Bean命名规则的源代码进行分析
4,根据上述源代码可以总结出Bean对象命名规则为:
在默认情况下,Bean名称为首字母小写的类名,但如果类名首字母和第二个字母都为大写,Bean名称为原类名。
1.5,类注解使用注意问题
1)<bean>
标签 能否和<content:component-scan>
标签一起使用?
解答:<bean>
标签 能和<content:component-scan>
标签一起使用,<bean>
可以是对<content:component-scan>
的补充。
- 使用
<context:component-scan>
标签扫描指定的包,并自动注册相应注解标识的类作为Bean - 使用
<bean>
标签定义和配置一些需要详细控制的特定Bean
2)五大类注解可以不在<content:component-scan>
标签内设置的指定包路径下使用吗?
解答:五大类注解不可以在<content:component-scan>
标签内设置的指定包路径以外的路径下使用。
理由:五大类注解(@Component
、@Controller
、@Service
、@Repository
等)需要在<context:component-scan>
标签内设置的指定包路径下使用,以便Spring能够正确扫描并注册这些类。
3)在<content:component-scan>
标签内设置的包路径下,如果没有添加五大类注解,能将Bean对象存储到Spring中吗?
解答:即使类在<content:component-scan>
标签内设置的包路径下,若没有添加五大类注解,也是不能把当前类对象存储到Spring。
4)如果存在相同的类对象在<content:component-scan>
标签内设置的扫描包的不同子包路径下,会发生异常么?
解答:若没有对相同的类对象添加别名,会发生BeanDefinitionStoreException
异常。
解决上述情况的方法:通过导入指定的包进行区分或者添加别名的方式进行区分,推荐使用后者(导包容易出现导错的情况)。
上述问题核心总结:为了确保Spring能够正确使用这些注解,需要将相关注解的使用限定在<context:component-scan>
标签内设置的指定包路径下的类中。若在其他包路径下的类中使用这些注解,需要通过显式的<bean>
标签进行定义和配置,进行手动注册。
2,方法注解@Bean
2.1,方法注解介绍及使用
类注解是添加到某个类上的,而方法注解是放到某个方法上的,方法注解@Bean的使用流程:
1)创建一个Student实体类
创建一个Student实体类操作代码:
public class Student {
private int studentId;
private String StudentName;
public int getStudentId() {
return studentId;
}
public void setStudentId(int studentId) {
this.studentId = studentId;
}
public String getStudentName() {
return StudentName;
}
public void setStudentName(String studentName) {
StudentName = studentName;
}
}
2)在其它类中使用@Bean存储对象
在其它类中使用@Bean存储对象操作代码:
import com.java.example.org.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
@Controller
public class StudentBeans {
@Bean
public Student student(){
Student student1 = new Student();
student1.setStudentId(1);
student1.setStudentName("小样");
return student1;
}
}
3)在启动类中检测是否成功存储对象
在启动类中检测是否成功存储对象操作代码:
import com.java.example.*;
import com.java.example.org.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//1,获取Spring上下文
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring-config.xml");
//2,得到Bean对象
Student student =
applicationContext.getBean("student",Student.class);
//3,使用Bean对象
System.out.println(student.getStudentName());
}
}
注意:@Bean命名规则和五大类注解的命名规则不同,默认情况下,@Bean存储的对象名称就是方法名。
在启动类中检测是否成功存储对象操作代码执行结果:
2.2,方法注解Bean重命名
方法注解Bean重命名可以使用两种字段进行,分别为 name
属性和 value
属性。
@Bean重命名的两种方式分别为:
注意: name
和 value
的本质是⼀个数组,可以存放多个值,也就是说⼀个 bean 可以有多个名字,并且 name={}
可以省略。
2.3,方法注解使用注意问题
1)@Bean 注解必须要与五大类注解配合使用,如果不搭配五大类注解使用会抛出如下异常:
2)当@Bean对象进行重命名之后,默认地使用方法名获取对象的方式就不能使用了,若使用,则会抛出如下异常:
核心总结
类注解的使用相关介绍?
1,类注解存在的原因:起到程序员看到类注解之后,就能直接知道当前类的作用和功能的效果。
2,@Controller
/@Service
/@Repository
/@Configuration
这四个类注解都属于@Component
的子类。
3,Bean命名规则:在默认情况下,Bean名称为首字母小写的类名,但如果类名首字母和第二个字母都为大写,Bean名称为原类名。
4,类注解的功能:处于被配置的扫描包路径下的所有的对象方法,经添加注解之后就能被正确的识别并保存到Spring 容器中。
类注解的使用注意事项?
1,<bean>
标签 能和<content:component-scan>
标签一起使用,<bean>
可以是对<content:component-scan>
的补充。
2,五大类注解不可以在<content:component-scan>
标签内设置的指定包路径以外的路径下使用。
3,即使类在<content:component-scan>
标签内设置的包路径下,若没有添加五大类注解,也是不能把当前类对象存储到Spring。
4,若没有对相同的类对象添加别名,会发生BeanDefinitionStoreException
异常。
方法注解的使用相关介绍?
1,方法注解使用的核心流程:在其它类中使用@Bean注解存储对象。
2,@Bean命名规则和五大类注解的命名规则不同,默认情况下,@Bean存储的对象名称就是方法名。
3,方法注解Bean重命名可以使用两种字段进行,分别为name
属性和value
属性,本质是⼀个数组,可以存放多个值。
方法注解的使用注意事项?
1,@Bean 注解必须要与五大类注解配合使用,如果不搭配五大类注解使用会抛出异常。
2,当@Bean对象进行重命名之后,默认地使用方法名获取对象的方式就不能使用了,若使用,则会抛出异常。