• 2023.11.6 Spring 使用注解存储 Bean 对象


    目录

    前置工作

    使用类注解

    五大类注解 

    @Controller(控制器)

    @Service(服务)

    @Repository(仓库)

    @Component(组件)

    @Configuration(配置)

    使用方法注解 @Bean

    重命名 Bean 

    补充问题

    类注解之间的关系


    前置工作

    • 在配置文件中配置好扫描路径

    1. "1.0" encoding="UTF-8"?>
    2. "http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:content="http://www.springframework.org/schema/context"
    5. 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">
    6. package="com.java.demo">

    使用类注解

    五大类注解 

    @Controller(控制器)

    • 归属业务逻辑层
    • 验证用户请求的数据正确性(安保系统)

    @Service(服务)

    • 归属服务层
    • 编排和调度具体的执行方法(客服中心)

    @Repository(仓库)

    • 归属持久层
    • 和数据库交互(执行者)

    @Component(组件)

    • 归属于公共工具类
    • 提供某些公共方法

    @Configuration(配置)

    • 归属于配置层
    • 用来配置当前项目的一些信息(对项目的全局配置负责)

    实例理解

    • 创建一个 StudentController 类,并使用 @Controller 注解将其注入到 Spring 容器中
    • 将该实例的 @Controller 注解换成 @Service、@Repository、@Component、@Configuration 均可实现将当前类注入到 Spring 容器中
    1. package com.java.demo;
    2. import org.springframework.stereotype.Controller;
    3. // 使用 @Controller 注解将当前类存储到 spring 容器中
    4. @Controller
    5. public class StudentController {
    6. public void sayHi() {
    7. System.out.println("student controller say hi");
    8. }
    9. }
    • 在启动类中获取 Bean 对象,并使用 Bean 对象
    1. import com.java.demo.StudentController;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class App {
    5. public static void main(String[] args) {
    6. // 得到 Spring 上下文对象
    7. ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    8. // 获取 Bean 对象
    9. StudentController studentController = context.getBean("studentController",StudentController.class);
    10. studentController.sayHi();
    11. }
    12. }
    • 此处我们并未在配置文件中使用 Bean 标签将 StudentController 对象注入到 Spring 容器中
    • 而是直接使用 @Controller 注解将其注入到 Spring 容器
    • 所以当我们要使用 getBean 方法获取该 Bean 对象的时候,其默认 id 为原类名的小驼峰形式

    运行结果:

    注意:

    • 此处的 Bean 对象的 id 命名还存在特殊情况 
    • 创建一个 SController 类
    1. import org.springframework.stereotype.Controller;
    2. @Controller
    3. public class SController {
    4. public void sayHi() {
    5. System.out.println("s controller say hi");
    6. }
    7. }
    • 在启动类中获取 Bean 对象,并使用 Bean 对象
    1. import com.java.demo.SController;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class App {
    5. public static void main(String[] args) {
    6. // 得到 Spring 上下文对象
    7. ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    8. // 获取 Bean 对象
    9. SController sController = context.getBean("sController",SController.class);
    10. sController.sayHi();
    11. }
    12. }

    运行结果:

    结论1:

    • 默认情况 Bean 对象 id 为原类名的小驼峰形式
    • 但如果类名的第一个字母和第二个字母都是大写,则其 Bean 对象 id 应为 原类名

    五大类注解 Bean 对象 id 命名规则原码


    结论2:

    • 在配置文件中, 标签和 标签可以同时使用
    • 标签可补充注入 不在扫描路径中的 Bean 对象

    实例理解

    • 创建一个 UserService 类
    1. public class UserService {
    2. public void sayHi() {
    3. System.out.println("user service say hi");
    4. }
    5. }
    • 使用 标签将 UserService 类的 Bean 对象注入到 Spring容器中

    • 在启动类中获取 Bean 对象并使用
    1. import com.java.service.UserService;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class App {
    5. public static void main(String[] args) {
    6. // 得到 Spring 上下文对象
    7. ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    8. // 获取 Bean 对象
    9. UserService userService = context.getBean("userService",UserService.class);
    10. userService.sayHi();
    11. }
    12. }

    运行结果:


    结论3:

    • 不在 中所设置的扫描路径下 且被五大类注解标识的类,不会注入到 Spring 容器中

    结论4:

    • 在  中所设置的扫描路径下 但未被五大类注解标识的类,不会注入到 Spring 容器中

    结论5:

    • 在   中所设置的扫描路径下的所有子包的类,只要加了五大类注解的类,会注入到 Spring 容器中

    使用方法注解 @Bean

    •  相比较于五大类注解 添加到某个类上
    • 方法注解 @Bean ,顾名思义就是将其添加到方法上的

    注意:

    @Bean 注解 必须要配合 五大类注解一起使用

    • 只有加了 五大类注解的类,Spring 才会 扫描该类
    • 进而才会扫描当前类中的方法是否有加了 @Bean 注解的
    • 这是出于 Spring 性能设计所规定的策略

    @Bean 注解 Bean 对象命名规则:

    • 默认情况下,@Bean 存储的 Bean 对象的 id 就是方法名

    实例理解

    • 我们创建一个 实例类 User
    1. // 普通的用户实体类
    2. public class User {
    3. public Integer uid;
    4. public String username;
    5. public String password;
    6. public Integer age;
    7. public Integer getUid() {
    8. return uid;
    9. }
    10. public void setUid(Integer uid) {
    11. this.uid = uid;
    12. }
    13. public String getUsername() {
    14. return username;
    15. }
    16. public void setUsername(String username) {
    17. this.username = username;
    18. }
    19. public String getPassword() {
    20. return password;
    21. }
    22. public void setPassword(String password) {
    23. this.password = password;
    24. }
    25. public Integer getAge() {
    26. return age;
    27. }
    28. public void setAge(Integer age) {
    29. this.age = age;
    30. }
    31. }
    • 我们再创建一个 UserBeans 类
    • 在该类中写一个方法,来创建 实例类 User 的对象
    • 并使用 @Bean 注解将 User 的 Bean对象 注入到 Spring 容器中
    • 注意此处搭配了五大类注解中的 @Component 注解
    1. import com.java.demo.entity.User;
    2. import org.springframework.context.annotation.Bean;
    3. import org.springframework.stereotype.Component;
    4. @Component
    5. public class UserBeans {
    6. @Bean
    7. public User user1() {
    8. User user = new User();
    9. user.setUid(1);
    10. user.setUsername("张三");
    11. user.setPassword("123456");
    12. user.setAge(18);
    13. return user;
    14. }
    15. }
    • 在启动类中获取该 Bean 对象
    • 注意此处获取 Bean 对象时的 id 为 user1,即被 @Bean 注解所修饰方法的方法名
    1. import com.java.demo.entity.User;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class App {
    5. public static void main(String[] args) {
    6. // 得到 Spring 上下文对象
    7. ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    8. // 获取 Bean 对象
    9. User user = context.getBean("user1",User.class);
    10. System.out.println(user.getUsername());
    11. }
    12. }

    运行结果:


    重命名 Bean 

    • 默认情况下,@Bean 存储的 Bean 对象的 id 就是方法名
    • 但是我们还是可以自己手动设置 Bean 对象的 id

    实例理解

    • 我们可以通过下图方式给 Bean 对象设置多个 id

    • 在启动类中获取该 Bean 对象
    • 此时我们任选一个 id 即可获取该 Bean 对象,此处选择 id 为 u1
    1. import com.java.demo.entity.User;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class App {
    5. public static void main(String[] args) {
    6. // 得到 Spring 上下文对象
    7. ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    8. // 获取 Bean 对象
    9. User user = context.getBean("u1",User.class);
    10. System.out.println(user.getUsername());
    11. }
    12. }

    运行结果:

    注意:

    • 当给 Bean 对象重命名之后,默认的使用方法名获取对象的方式就不能再使用了

    补充问题

    • 我们创建一个 UserBeans 类,且未重命名 Bean 对象
    1. import com.java.demo.entity.User;
    2. import org.springframework.context.annotation.Bean;
    3. import org.springframework.stereotype.Component;
    4. @Component
    5. public class UserBeans {
    6. @Bean
    7. public User getUser() {
    8. User user = new User();
    9. user.setUid(1);
    10. user.setUsername("张三");
    11. user.setPassword("123456");
    12. user.setAge(18);
    13. return user;
    14. }
    15. }
    • 我们再创建一个 UserBeans2 类,且未重命名 Bean 对象
    1. import com.java.demo.entity.User;
    2. import org.springframework.context.annotation.Bean;
    3. import org.springframework.stereotype.Component;
    4. @Component
    5. public class UserBeans2 {
    6. @Bean
    7. public User getUser() {
    8. User user = new User();
    9. user.setUid(2);
    10. user.setUsername("李四");
    11. user.setPassword("123456");
    12. user.setAge(20);
    13. return user;
    14. }
    15. }
    • 在启动类中获取该 Bean 对象
    1. import com.java.demo.entity.User;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class App {
    5. public static void main(String[] args) {
    6. // 得到 Spring 上下文对象
    7. ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    8. // 获取 Bean 对象
    9. User user = context.getBean("getUser",User.class);
    10. System.out.println(user.getUsername());
    11. }
    12. }

    运行结果:

    • 我们多次运行启动类,发现所获取到始终是 Username 为李四的 Bean 对象
    • 但是 Username 为张三的 Bean 对象,其 id 也为 getUser,但是为什么获取的不是它呢?
    • 此处涉及到数据覆盖
    • 因为 Username 为张三 且 id 为 getUser 的 Bean 对象,先被注入到 Spring 容器中
    • 此时 Username 为李四 且 id 为 getUser 的 Bean 对象,再被注入到 Spring 容器中
    • 正因为 Spring 容器中已经又了 id 为 getUser 的 Bean 对象,所以后注入到的 Username 为李四 的 Bean 对象 便将 Username 为张三 的 Bean 对象 给覆盖了
    • 所以此处启动类获取到的 Bean 对象其 Username 输出为 李四

    我们可以通过 @Oder 注解来更清晰的观察该情况

    • @Oder 注解 是用来控制 Bean 对象注入顺序
    • 其参数值越小,其权重就越大,也就越先被注入到 Spring 容器中

    类注解之间的关系

    注意:

    • @Controller、@Service、@Repository、@Configuration 均是针对 @Component 的一个扩展
    • 这几个注解均能将当前类注入到 Spring 容器中,其功能基本一致
    • 之所以分这么多类注解,其原因就是:
    • 能让程序员看到注解之后便知道当前类的作用

    上述类注解对应着 JavaEE 标准分层(至少三层)

    1. 控制层
    2. 服务层
    3. 数据持久层
    • 当一个类不合适放在上面三层中的任意一个时,可用 @Component 注解进行分层的扩展和补充
  • 相关阅读:
    Java高频面试复习题,助你吊打面试官
    【docker快速部署微服务若依管理系统(RuoYi-Cloud)】
    Gateway--服务网关
    关于ip地址的网页无法访问navigator的gpu、媒体、蓝牙等设备的解决方法
    以C之名,解析Xml
    round函数四舍五入结果不对
    yarn的安装与使用
    第4季2:并口、MIPI、LVDS的简介
    RK3399平台开发系列讲解(内核调试篇)2.51、什么是硬件断点
    docker安装es docker安装Elasticsearch windows linux
  • 原文地址:https://blog.csdn.net/weixin_63888301/article/details/134233657