【Spring】(三)Spring 使用注解存储和读取 Bean对象

文章目录

  • 前言
  • 一、使用注解储存 Bean 对象
    • 1.1 配置扫描路径
    • 1.2 类注解储存 Bean 对象
      • 1.2.1 @Controller(控制器存储)
      • 1.2.2 @Service(服务储存)
      • 1.2.3 @Repository(仓库存储)
      • 1.2.4 @Component(组件储存)
      • 1.2.5 @Configuration(配置储存)
      • 1.2.6 Bean 命名规则
    • 1.3 五大类注解的作用
      • 1.3.1 为什么有这么多的注解
      • 1.3.2 类注解之间的关系
    • 1.4 方法注解储存 Bean 对象
      • 1.4.1 @Bean 注解的使用
      • 1.4.2 Bean 对象重命名
  • 二、使用注解获取 Bean 对象
    • 2.1 Bean 对象通过注解获取的方法
    • 2.2 三种注入方法的使用
      • 2.2.1 属性注入
      • 2.2.2 Setter 注入
      • 2.2.3 构造方法注入
    • 2.3 三种注入方法的优缺点
    • 2.4 @Resource 注入
    • 2.5 @Autowired 和 @ Resource的区别
    • 2.6 注入同一类型的多个 @Bean 报错问题
      • 2.6.1 报错问题
      • 2.6.2 使用 @Resource(name="XXX") 解决
      • 2.6.3 @Autowired 配合使用 @Qualifier 解决


前言

前面的文章详细的介绍了 Spring 对象的创建,以及对 Bean 对象的存取操作,但是通过配置文件注册 Bean 对象以及使用 ApplicationContextBeanFactory 的方式获取 Bean 对象的操作就显得格外的复杂。因此,本文主要就是详细介绍了一种更加简单的方式来实现对 Bean 对象更加简单的储存和读取操作。

在 Spring 中,要想更加简单的实现对 Bean 对象的储存和使用,其核心就是使用注解,本文主要就是演示如何使用注解实现对 Bean 对象的存取操作。

一、使用注解储存 Bean 对象

在之前储存 Bean 对象的时候,还需在 spring-congig 文件中添加一行 <bean> 内容才行,而且,每需要新增一个 Bean 对象到 Spring 容器中就需要新增一行,这样的操作就显得非常麻烦了。

而现在只需要使用一个注解就能代替这一行 <bean> 内容,此时就变得非常方便。想要通过注解的方式将对象储存到 Spring 容器中,主要有两种注解类型可以实现:

  1. 使用类注解(五大类注解):

    • @Controller(控制储存):验证用户请求的数据合法性,相当于安保系统;
    • @Service(服务储存):用于编排和调度具体的执行方法;
    • @Repository(仓库储存):持久层,与数据库进行交换;
    • @Component(组件储存):相当于工具类;
    • @Configuration(配置储存):项目中的一些配置。
  2. 使用方法注解:

    • @Bean:作用在方法上,需要配合上述的类注解使用。

但在此之前还需要配置一下扫描路径

1.1 配置扫描路径

spring-config.xml文件中添加如下一行记录:

其含义是,指定一个 base package,即所有需要添加到 Spring 容器中的 Bean 对象都在 base package 所指定包或者其子包下。这里我知道的包是com.spring.demo,那么就意味着,如果不是此包下的 Bean 对象,即使加上了注解,也不会被添加到 Spring 容器中。

1.2 类注解储存 Bean 对象

1.2.1 @Controller(控制器存储)

使用 @Controller 注解储存 Bean 对象:

@Controller
public class StudentController1 {public void sayHi(){System.out.println("do studentController1 sayHi().");}
}

使用 ApplicationContext的方式获取 Bean 对象:

public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");StudentController1 studentController1 =context.getBean("studentController1", StudentController1.class);studentController1.sayHi();
}

关于 Bean 对象的命名规则可见后文。

1.2.2 @Service(服务储存)

使用 @Service 注解储存 Bean 对象:

@Service
public class StudentController2 {public void sayHi(){System.out.println("do studentController2 sayHi().");}
}

获取 Bean 对象:

StudentController2 studentController2 =context.getBean("studentController2", StudentController2.class);

1.2.3 @Repository(仓库存储)

使用 @Repository 注解储存 Bean 对象:

@Repository
public class StudentController3 {public void sayHi(){System.out.println("do studentController3 sayHi().");}
}

获取 Bean 对象:

StudentController3 studentController3 =context.getBean("studentController3", StudentController3.class);

1.2.4 @Component(组件储存)

使用 @Component 注解储存 Bean 对象:

@Component
public class StudentController4 {public void sayHi(){System.out.println("do studentController4 sayHi().");}
}

获取 Bean 对象:

StudentController4 studentController4 =context.getBean("studentController4", StudentController4.class);

1.2.5 @Configuration(配置储存)

使用 @Configuration 注解储存 Bean 对象:

@Configuration
public class StudentController5 {public void sayHi(){System.out.println("do studentController5 sayHi().");}
}

获取 Bean 对象:

StudentController5 studentController5 =context.getBean("studentController5", StudentController5.class);

1.2.6 Bean 命名规则

通过上述代码可以发现,在创建 Bean 对象的时候,都是使用的标准 “大驼峰” 的命名方式,而读取的时候 Bean 的名称则是其类名称的首字母小写,即小驼峰。


但是,此时创建一个 SController 类,并使用注解将其添加到 Spring 容器中,那么此时它的 Bean 对象的名称是什么呢?根据上面代码的规律,难道还是SController 吗?

SController sController = context.getBean("sController", SController.class);

当运行程序的时候,发现报错了:

其意思是不存在名称为 sController 这样 Bean 对象。此时如果将其改成 SController,会是正确的吗?


此时发现便能正常运行了。

关于 Bean 的名称生成的源码:

  1. 查找 beanname,选择AnnotationBeanNameGenerator
  2. 继续查找

  1. 继续查找


4. 找到了源码,即Introspector类下的decapitalize 方法

该方法通过检查字符串的首字母是否为大写,并且第二个字符也是大写的情况下,直接返回原字符串,不做小写化处理。这样做是为了避免一些特殊情况下,例如缩写或首字母缩写词,不被误处理。

1.3 五大类注解的作用

在Spring框架中,五大类常用的注解,分别是:@Component、@Controller、@Service、@Repository和@Configuration。

  • @Component: 通用的组件注解,表示类是一个Spring管理的组件(Bean)。

  • @Controller: 用于标识控制器类,通常用于Spring MVC中,处理HTTP请求和视图渲染。

  • @Service: 用于标识服务类,表示该类提供一些业务逻辑处理。

  • @Repository: 用于标识仓库类,表示该类用于数据访问,通常与数据库交互。

  • @Configuration: 用于标识配置类,表示该类包含Spring配置信息,通常与@Bean一起使用,用于定义 Bean。

1.3.1 为什么有这么多的注解

通过上面代码的演示,发现这些注解的功能都是一样的,既然都是一样的为什么还需要有这么多不同的注解呢?

Spring 之所以提供这么多的注解,是为了更好的组织和管理应用程序的组件和依赖关系因为每个注解都有自己特定的用途,让开发人员在应用程序中能够更方便地标识和区分不同类型的类。同时也提现了程序的工程分层:

  1. 其中 @Controller 表示的是控制层,负责与用户进行交互,以及验证用户提交数据的合法性;
  2. @Service表示的是服务层,用于编排和调度具体的执行方法,相当于车站中的服务台;
  3. @Repository表示的是持久层,负责将数据持久化储存,通常需要与数据库进行交互。

以上三个层次实现了程序的工程分层,同时也是 Java EE 标准分层的最核心分层。

1.3.2 类注解之间的关系

  • 查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:
    它们都是 @Component 子类注解,这意味着,被标注为 @Controller / @Service / @Repository / @Configuration 的类也被视为@Component

  • 另外,@Configuration注解是一个特殊的注解,它表明该类是 Spring 的配置类,用于定义 Bean 和配置应用程序的其他元素。配置类中的@Bean注解用于定义 Bean。

1.4 方法注解储存 Bean 对象

首先创建一个 User 实体类:

package com.spring.demo.entity;/*** 普通的用户实体类*/
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;}@Overridepublic String toString() {return "User{" +"uid=" + uid +", username='" + username + '\'' +", password='" + password + '\'' +", age=" + age +'}';}
}

1.4.1 @Bean 注解的使用

创建一个组件类 UserBeans,并使用方法注解 @Bean 将 User 类添加到 Spring 容器中:

@Controller
public class UserBeans {@Beanpublic User getUser(){User user = new User();user.setUid(1);user.setUsername("王五");user.setPassword("123456");user.setAge(18);return user;}
}

注意,使用方法注解 @Bean 的时候需要搭配五大类注解才能生效。

获取 Bean 对象:

public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");User user = context.getBean("getUser", User.class);System.out.println(user);
}

注意,当使用方法注解@Bean 的时候,Bean 对象的默认名称就是其 添加到 Spring 容器中的方法名。

1.4.2 Bean 对象重命名

如果直接使用方法名作为 Bean 对象的名称,例如getUser就显得非常的不合理,因此往往需要对 Bean 进行改名操作。但查看@Bean源码的时候可以发现,其中的namevalue属性是一个数组,那么就意味着可以一个 Bean 对象取多个名称。

例如:

此时,可通过这两个名称,获取该 Bean 对象,发现它们是同一个 Bean:

另外需要注意的是,如果对 Bean 进行了重命名,则原来默认的方法名就失效了。

二、使用注解获取 Bean 对象

2.1 Bean 对象通过注解获取的方法

获取 Bean 对象也叫做对象装配,即把对象取出来放到某个类当中,同时也叫做对象注入

对象注入的实现方式有以下三种:

  1. 属性注入:属性注入是通过在属性上使用注解实现的。常见的注解有@Autowired@Resource。属性注入是在 Bean 对象的属性上直接进行注入,不需要提供setter方法。

  2. Setter 注入Setter 注入是通过在 Bean 对象的 setter 方法上使用注解实现的。这种注入方式是在调用 Bean 的 setter 方法时,将依赖对象作为参数传入。

  3. 构造方法注入:构造方法注入是通过在 Bean 对象的构造方法上使用注解实现的。这种注入方式是在创建 Bean 对象的时候,通过构造方法参数传入依赖对象。

2.2 三种注入方法的使用

下⾯按照实际开发中的模式,将 Service 类注入到 Controller 类中,然后通过 main 方法获取 Controller 中的 Bean 对象。
首先创建一个 UserService 类和 UserController 类:


@Service
public class UserService {public void sayHi(){System.out.println("hi, userService.");}
}

2.2.1 属性注入

@Controller
public class UserController {// 1. 属性注入@Autowiredprivate UserService userService;public void sayHi(){System.out.println("do userController sayHi().");userService.sayHi();}
}

2.2.2 Setter 注入

@Controller
public class UserController {// 2. setter 注入private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("do userController sayHi().");userService.sayHi();}
}

2.2.3 构造方法注入

@Controller
public class UserController {// 3. 构造方法注入private UserService userService;// @Autowiredpublic UserController(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("do userController sayHi().");userService.sayHi();}
}

注意,如果此时只有一个构造方法,则@Autowired 可以省略。

2.3 三种注入方法的优缺点

属性注入

  1. 优点:简洁,代码量少,适合对属性直接注入的情况;
  2. 缺点:
    • 对于必须注入的属性,如果没有找到匹配的Bean,会导致运行时错误;
    • 兼容不好,只能用于 IoC 容器;
    • 没办法实现 finally 修饰的变量实现注入;
    • 过于简单,容易违背单一设计原则。

Setter注入:

  1. 优点:符合单一设计原则,每个方法只能传递一个对象。

  2. 缺点:

    • 没办法实现 finally 修饰的变量实现注入;
    • 使用 Setter 注入的对象可能会被修改。

构造方法注入:

  1. 优点:

    • 可以实现 finally 修饰的变量实现注入;
    • 注入的对象不会被改变,即构造方法只能执行一次;
    • 构造方法注入可以保证注入对象完全被初始化。
  2. 缺点:构造方法参数较多时,代码显得冗长。

2.4 @Resource 注入

在进行类注入时,除了可以使用 @Autowired 关键字之外,我们还可以使用 @Resource 进行注入,如下代码所示:

属性注入:

public class UserController {// 1. 属性注入@Resourceprivate UserService userService;public void sayHi(){System.out.println("do userController sayHi().");userService.sayHi();}
}

Setter注入:


@Controller
public class UserController {// 2. setter 注入private UserService userService;@Resourcepublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("do userController sayHi().");userService.sayHi();}
}

遗憾的是,@Resource 不支持构造方法注入:

2.5 @Autowired 和 @ Resource的区别

  1. @Autowired是 Spring 框架提供的注解,而 @Resource 是JSR-250规范提供的注解,但是 Spring 也对其进行了支持。
  2. @Autowired 默认按照类型装配 Bean,如果多个类型匹配,可以配合 @Qualifier 注解指定具体的 Bean 名称。而 @Resource 默认按照属性名进行装配,可以通过 name 属性指定具体的 Bean 名称。
  3. @Autowired 是 Spring 的专有注解,更加灵活,功能更强大。@Resource 是标准的 Java 注解,适用于更通用的情况
  4. @Autowired 可用于 Setter 注入、构造函数注入和属性注入,而 @Resource 只能用于 Setter 注入和属性注入,不能用于构造函数注入。

2.6 注入同一类型的多个 @Bean 报错问题

当存在多个类型相同的 Bean 对象,并且需要通过注解将其注入到其他 Bean 对象中时,如果没有明确指定注入哪个 Bean,就会导致报错。

2.6.1 报错问题

例如,通过 Component 中的 UserBeans 将 User 注入到 Controller 中的 UserController 中。

首先,在UserBeans 使用@Bean 添加两个 User 对象到 Spring 容器中:

@Controller
public class UserBeans {@Bean(name = {"user1", "u1"})public User getUser1(){User user = new User();user.setUid(1);user.setUsername("张三");user.setPassword("123456");user.setAge(18);return user;}@Bean(name = "user2")public User getUser2(){User user = new User();user.setUid(1);user.setUsername("李四");user.setPassword("123456");user.setAge(18);return user;}
}

UserController 中分别使用 @Autowired@Resource注入获取 Bean 对象:

@Autowired

此时,由于存在两个相同类型的 Bean 对象,但是其名称不同,所以使用@Autowired注解不知道获取哪个对象。

@Resource

使用@Resource注解同样无法判断获取哪一个对象。

关于@Autowired@Resource 查找 Bean 对象的顺序:

  • @Autowired首先按照类型查找,然后再按照名称查找;
  • @Resource首先按照名称查找,然后再按照类型查找。

2.6.2 使用 @Resource(name=“XXX”) 解决

@Controller
public class UserController {@Resource(name = "user1")private User user;public void sayHi(){System.out.println("do userController sayHi().");}
}

2.6.3 @Autowired 配合使用 @Qualifier 解决

@Controller
public class UserController {@Autowired@Qualifier(value = "user1")private User user;public void sayHi() {System.out.println("do userController sayHi().");}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/83756.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

查看CentOS版本及系统位数与设置CentOS 7.9 2009 防火墙配置放开端口的命令与过程

一、查看CentOS版本及系统位数 1.1 命令汇总 //1、安装redhat-lsb yum install -y redhat-lsb//2、查看系统版本信息 lsb_release -a //3、查看系统位数 getconf LONG_BIT1.2 截图 二、设置CentOS7.9 2009 防火墙配置放开端口 2.1 命令汇总 //禁止防火墙开机启动。这种方法方…

【深度学习】采用自动编码器生成新图像

一、说明 你知道什么会很酷吗&#xff1f;如果我们不需要所有这些标记的数据来训练 我们的模型。我的意思是标记和分类数据需要太多的工作。 不幸的是&#xff0c;大多数现有模型从支持向量机到卷积神经网&#xff0c;没有它们&#xff0c;卷积神经网络就无法训练。无监督学习不…

国产芯力特Mini LIN SBC SIT1028Q应用方案,可替代TJA1028

SIT1028Q是一款内部集成高压LDO稳压源的本地互联网络&#xff08;LIN&#xff09;物理层收发器&#xff0c;可为外部ECU&#xff08;Electronic Control Unit&#xff09;微控制器或相关外设提供稳定的5V/3.3V电源&#xff0c;该LIN收发器符合LIN2.0、LIN2.1、LIN2.2、LIN2.2A、…

umi快速搭建中后台管理系统(命令行创建和区块开发的区别)

后台管理系统 命令行创建新项目命令行效果图配置文件package.json umi3构建区块readme.md主页面页面布局页面布局的一些参数总结 区块开发步骤三级目录 命令行创建新项目 命令行 1、 npm i ant-design/pro-cli -g 2、 pro create demo_spacemv_managementsys 3、 umi 3 simpl…

《合成孔径雷达成像算法与实现》Figure3.7

代码复现如下&#xff1a; clc clear all close all%参数设置 TBP 100; %时间带宽积 T 10e-6; %脉冲持续时间%参数计算 B TBP/T; …

【Vue3】自动引入插件-`unplugin-auto-import`

Vue3自动引入插件-unplugin-auto-import&#xff0c;不必再手动 import 。 自动导入 api 按需为 Vite, Webpack, Rspack, Rollup 和 esbuild 。支持TypeScript。由unplugin驱动。 插件安装&#xff1a;unplugin-auto-import 配置vite.config.ts&#xff08;配置完后需要重启…

Jmeter(五) - 从入门到精通 - 创建网络计划实战和创建高级Web测试计划(详解教程)

1.简介 上一篇中已经将其的理论知识介绍了一下&#xff0c;这一篇就带着大家一步一步的把上一篇介绍的理论知识实践一下&#xff0c;然后再说一下如何创建高级web测试计划。 2.网络计划实战 通过上一篇的学习&#xff0c;将其分类为&#xff1a; &#xff08;1&#xff09;不需…

本质矩阵E、基本矩阵F、单应矩阵H

1. E (归一化坐标对进行计算) t ^ R 为3*3的矩阵, 因为R,t共有6个自由度&#xff0c;又因为单目尺度等价性&#xff0c;所以实际上E矩阵共有5个自由度。因此至少需要5个点对来求解。 2. 基本矩阵F:根据两帧间匹配的像素点对儿计算 3*3且自由度为7的矩阵kF也为基础矩阵&#x…

直播招聘小程序解决方案

项目开发愿景 介绍工作拿佣金&#xff0c;Boss直播现真身。做为直播招聘的新平台&#xff0c;让求职和招聘变得更简单&#xff01;企业发布招聘视频&#xff0c;展现公司环境与实力&#xff0c;开通会员可以直播招聘、在线面试功能&#xff1b;求职者刷视频可以刷到工作…

shopify独立站运营操作步骤?如何经营管理?

如何进行shopify独立站运营流程?shopify的自主网站管理过程? 在如今数字化的商业世界中&#xff0c;建立和管理自己的在线商店变得越来越重要。shopify独立站运营成为了许多创业者的首选。本文将为您介绍一些关键的操作步骤&#xff0c;帮助您顺利开展shopify独立站运营&…

【数学建模】--主成分分析

本讲将介绍主成分分析&#xff08;Principal Component Analysis&#xff0c;PCA&#xff09;&#xff0c;主成分分析是一种降维算法&#xff0c;它能将多个指标转换为少数几个主成分&#xff0c;这些主成分是原始变量的线性组合&#xff0c;且彼此之间互不相关&#xff0c;其能…

Vue中data变量使用的注意事项

因为在Vue中&#xff0c;data中的属性往往都是用于双向绑定&#xff0c;所以Vue会对其有劫持&#xff0c;所以我们在对data属性进行操作时&#xff0c;尽量不要对其直接操作&#xff0c;比如下面代码&#xff1a; export default {data() {return {list: []}},methods: {init(…

MIT6.006 课程笔记P1 - 思考如何进行 PeakFinding

文章目录 寻找峰值 peak暴力算法分而治之从1D到2D朴素算法Attemp#2 寻找峰值 peak 给出一个数组 a b c d e f g h i 并给予数字 index 1 2 3 4 5 6 7 8 9 那么如果某个数字是 peak &#xff0c;那么他将 大于等于左边的数 且 大于等于右边的数 或者 a > b 这里的 a 也是峰值…

fastadmin、vue、react图标库适用于多种框架

在二开fastadmin中&#xff0c;在写vue以及react时&#xff0c;侧边导航栏以及按钮中常常需要很多图标&#xff0c;那么这些图标应该去哪里得到呢&#xff0c;在这里给大家一个链接&#xff0c;这里有丰富的图标库&#xff0c;可以找到自己想要的进行使用。 点击下方链接&…

Leetcode-每日一题【剑指 Offer 13. 机器人的运动范围】

题目 地上有一个m行n列的方格&#xff0c;从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动&#xff0c;它每次可以向左、右、上、下移动一格&#xff08;不能移动到方格外&#xff09;&#xff0c;也不能进入行坐标和列坐标的数位之和大于k的格子。例…

【自然语言处理】大模型高效微调:PEFT 使用案例

文章目录 一、PEFT介绍二、PEFT 使用2.1 PeftConfig2.2 PeftModel2.3 保存和加载模型 三、PEFT支持任务3.1 Models support matrix3.1.1 Causal Language Modeling3.1.2 Conditional Generation3.1.3 Sequence Classification3.1.4 Token Classification3.1.5 Text-to-Image Ge…

K8S系列文章之 自动化运维利器 Ansible

Ansible-安装 第一步&#xff1a;安装我们的epel扩展源 yum -y install epel-release 我这里会报/var/run/yum.pid 已被锁定&#xff0c;如果没有直接进行下一步 [rootmaster home]# yum -y install epel-release 已加载插件&#xff1a;fastestmirror, langpacks /var/run/…

基于Pyqt5+serial的串口电池监测工具

本章,其他的没有,废话没有,介绍一下新开源了一个公司的测试工具,写了差不多三周吧。先来看看界面: 这是一个串口调试界面,使用Pyqt5+serial完成。升级功能暂未移入,占一个坑位。 基于serial二次开发的功能各位如有需要可以照搬走,这是一个纯手写的轮子,稳定! 左侧使用…

【网络基础知识铺垫】

文章目录 1 :peach:计算机网络背景:peach:1.1 :apple:网络发展:apple: 2 :peach:协议:peach:2.1 :apple:协议分层:apple:2.2 :apple:OSI七层模型:apple:2.3 :apple:TCP/IP模型:apple:2.4 :apple:TCP/IP模型与操作系统的关系:apple: 3 :peach:网络传输基本流程:peach:4 :peach:网…

Apache2.4源码安装与配置

环境准备 openssl-devel pcre-devel expat-devel libtool gcc libxml2-devel 这些包要提前安装&#xff0c;否则httpd编译安装时候会报错 下载源码、解压缩、软连接 1、wget下载[rootnode01 ~]# wget https://downloads.apache.org/httpd/httpd-2.4.57.tar.gz --2023-07-20 …