Spring 更简单的读取和存储对象

目录

前言

1、存储 Bean 对象

1.1、前置工作:配置扫描路径(重要)

1.2、简单的将 bean 存储到容器

1.2.1 使用 5 大类注解实现将 bean 存储到 容器

@Controller 注解

思考一个问题

问题二:五大类注解之间有什么关系?

问题三:关于 bean id 的命名,为什么是小驼峰结构?

1.2.2 使用 方法注解 @Bean 将 bean更简单的存入容器。

2、获取 Bean 对象(对象装配)

2.1 属性注入

2.1.1 @Autowired 注解 (Spring)

2.1.2  @Resource 注解  (JDK)

2.1.3 @Autowired 搭配 @Qualifier  注解

2.2 构造方法注入

2.3  Setter 注入

拓展1:经典面试题 -> 属性注入 ,构造方法注入 和 Setter 注入 之间,有什么区别?

拓展2:@Resource VS @Autowired 的区别

总结


前言

经过前⾯的 Spring 创建 和 使⽤的博文学习,我们已经可以实现基本的 Spring 读取和存储对象的操作了。
但在操作的过程中我们发现读取和存储对象并没有想象中的那么“简单”,所以接下来我们要学习更加简单的操作 Bean 对象的⽅法。

在 Spring 中想要更简单的存储和读取对象的核⼼是使⽤注解,也就是我们接下来要学习 Spring 中的相关注解,来存储和读取 Bean 对象。 

需要注意的是:
Spring 中的 注解是通用的。
即:在 Spring Boot 和 Spring MVC 中,使用 Spring 的注解。
它们 是能够完全识别并使用的。

也就是说:接下来,才是重点。
这些注解,将会是我们以后在工作中,在Spring系列的项目中,最常使用的知识!!!
这些注解的功能,必须掌握!!! 

1、存储 Bean 对象

之前我们存储 Bean 时,需要在 spring-config 中添加⼀⾏ bean 注册内容才⾏,如下图所示:

 这种存入 Bean 的方式,并不是很好!
        1、需要手动添加 bean 对象 到 配置文件中
        2、如果 是配置文件中出现了问题,不好调试。

这么说吧:如果 配置文件 出现了 问题,它是不会影响到程序的运行的。
它不会像 抛异常 一样,来 “显式” 的 打印 错误信息栈,描述具体的错误位置。
配置文件出现问题,它是“默不做声”的!【没有错误提示的】
除非你经验老道,否则你很难会想到是 它 出了问题。

⽽现在我们只需要⼀个注解就可以替代之前要写⼀⾏配置的尴尬了,不过在开始存储对象之前,我们先要来点准备⼯作。

简单来说:
  就是通过利用 注解,来简化  存入 / 取出  Bean(对象)的步骤。 

1.1、前置工作:配置扫描路径(重要)

如果不做这一步,后面所有的操作,都是无效的。

注意:
想要将对象成功的存储到 Spring 中,我们需要配置⼀下存储对象的扫描包路径.
只有被配置的包下的所有类,添加了注解才能被正确的识别并保存到 Spring 中。
即:注释 就像是 一个“桥梁”,将注释的 bean,“送往(存入)” Spring中。
但是!有一些步骤还是不能省略的!
比如创建项目,引入 Spring 框架的支持。

1、创建一个普通的 Maven 项目 (这个和之前的一样)

 创建一个启动类 和 main 方法。

2、引入 Spring 框架的支持 (这个和之前的一样)

将下面我给的 依赖,复制粘贴到 pom.xml 中。
就是一开始进入项目,显示页面文件

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.3.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.2.3.RELEASE</version></dependency>
</dependencies>

在resources 目录下,创建一个 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"><content:component-scan base-package=""></content:component-scan>
</beans>

准备工作,到此就结束!
下面,我们就可以开始尝试:使用更简单的方式(使用注解) 来 存储/取出 bean。


1.2、简单的将 bean 存储到容器

一共有两者方法:
1、使用 5 大类注解实现

  1. @Controller 【Controller - 控制器】
  2. @Service 【service - 服务】
  3. @Repository 【repository - 仓库】
  4. @Configuration 【configuration - 配置/布局】
  5. @Component 【component - 组件】

通过上述五大类注解中的任何一个,都可以将 bean 存储到 Spring 中。

2、通过 方法注解@Bean ,也可以将 一个 bean 存储到 Spring 中。
 

1.2.1 使用 5 大类注解实现将 bean 存储到 容器

@Controller 注解

为了验证 注解 的 效果,我们先来在 beans 目录中,创建一个 User 类。

 

由此,不难得出结论:要存入 Spring 中的 bean,必须处于 根目录下,而且注解不可省略!


思考一个问题

为什么?我们的 Spring 一定要有下面这个配置呢?

如果没有这个配置,意味着什么??

大家可以想象一下:
一个 Spring 项目中,我们的类可分两种类型:

  1. 需要 进行 控制反转的类,将类的“生命周期”交给 Spring 来管理的类。【比如:这里的UserController】
  2. 不需要存入 Spring 中的 类。


假设,我们有一个大型项目,需要存入 Spring 的 类 和 不需要存入 Spring 中的类,个数占比是五五开的。这就会存在问题了!
如果我们没有 描述 根目录 的 这一行代码,Spring 就会去扫描 所有的类,但是!项目中 需要存入 Spring 中的类,只占 50 %。即:Spring 要浪费一倍的时间,去排查 不需要 存入 Spring 中的类。所以,Spring 为了 提升效率,你必须要给我指定扫描的目录。保证该目录下,一定是需要存入 Spring中的类。这样 Spring就只需要扫描 对应目录中的类,就可以了!

再思考一个问题:

如果 根目录“beans”下面,还有子目录b。
我们将 UserController 类 存放到 b 中,会不会被加载呢? 

        虽然bean标签用起来比较的麻烦,但有些类确实不合适用注解,这个时候就可以用bean标签的方式来补充。所以允许两种方法一起使用。

 剩下四个注解,与上面一样的配方


 问题一:为什么需要五大类注解?

这就涉及到 软件工程方面的知识了!

 之所以讲这个 关于“软件分层” 的定义呢,就是为了 后面讲解 “为什么要有五大注解类” 做铺垫!


那么,问题来了,为什么不直接弄一个 “集大成者” 的注解呢?
一个注解当五个用!

这和为什么每个省/市都有⾃⼰的⻋牌号是⼀样的!
⽐如:陕⻄的⻋牌号就是:陕X:XXXXXX ;北京的⻋牌号:京X:XXXXXX;甚⾄⼀个省不同的县区也是不同的。⻄安就是,陕A:XXXXX,宝鸡,陕C:XXXXXX,⼀样
这样做的好处除了可以节约号码之外,更重要的作⽤是可以直观的标识⼀辆⻋的归属地。

五大类注解,就是为了避免 混淆的情况出现,所以针对 类的不同场景,进行分层。

每个注解负责的层次,是不一样的。但是只需要处理 各自负责的事务,就可以了。这就能提高执行的效率。

可能有些人的想法比较奇特:

为什么你就不能为 每个 层次的代码,创建一个目录,把 对应的代码 都放在 对应的目录下,
等到你需要查看这个类,是属于那一层的时候。
直接访问这个类所处于的目录,看看这个类是在 哪个目录底下嘛?
不就行了嘛!
注意!这样做,会产生 2个 有难度的操作!
1、我们得去扫描项目的每个路径,来获取这个类所处的目录【层次】。 

2、将本应该处于某一层的类,创建到另一层里面去了,我们还不知道,怎么办?
这是非常难以判断!你的类又没有移动!因为你直接创建到另一层中的。

如果是使用的注解,那就简单多了。

这就好比:每一辆车都有它们自己地区信息的牌照。
直接 针对 该地区中的车牌,进行查找对应的信息。
不必在全国的范围中,进行搜索。
查询的基数大大降低,查找效率大大提高!

得出结论:
使用 五大类注解,是为了让代码的可读性提高,让程序员能够更直观的判断当前类的业务用途。 


问题二:五大类注解之间有什么关系?

这五个类注解实现的功能 都是一样的,只是“长得”不一样。
那么,这 五个类注解之间,有什么关系呢?

结论:Component 注解,与其它四大注解,呈 “父子” 关系。

Controller,Service, Repository,configuration注解, 都是基于 Component 注解实现的。


问题三:关于 bean id 的命名,为什么是小驼峰结构?

在我们前面演示 五大类注解 的时候,我们其实就猜出了 bean id,默认是小驼峰。

但是!这一块有一个特例!!

 

 验证一下:

 到这里,我们就明白了 bean 的命名规则。
但是!最好还是 不要斜侧 APIController 这种形式。
虽然能执行,但是不符合规范。
最好,还是写 UserController 这种。
生成的 bean Name 是 小驼峰,才是“正统”!


1.2.2 使用 方法注解 @Bean 将 bean更简单的存入容器。

同时,我有验证了一下 beanName,发现和 beanName 是没有关系的!

就是因为 @Bean 注解,需要搭配五大类注解 来使用

同时,说明了 方法的 beanName 就是 方法名。
不需要 大驼峰,或者 小驼峰的格式。
直接照搬!
你们需要注意的是:方法 和 类 的命名规则,不是同一个!
因此,管你是大骆驼,还是小骆驼,都是不行滴!
只能使用 方法的原名!!!! 


 重命名 Bean

大家来思考一个问题:
真的在公司里工作,方法的名字,我们会取 像 user1 这么low的名字嘛?
答案:否定的! 公司对代码,是由规范要求的!

而且,相信大部分朋友,可能都喜欢 将其命名为 getUser.在这里插入图片描述

又或者是通过某种条件,来获取对象。
比如:name 和 id,即 getUserByName,getUserById ,这种命名方式。
相信是部分朋友的“习惯”。


虽然这么命名,也能获取到对象。在这里插入图片描述

 这么说吧:我们 想要获取的是 bean对象,你填一个 方法名,好像有点不太合适吧?
难道我们就不能使用 像类名的 命名规则 给 方法 重命名吗?
答案:有的!!!

这里需要注意一点: 如果方法被重命名,原先的方法名,就没用了!

结论:
@Bean 命名规则,当没有设置 name 属性时,那么 beanName 默认就是 方法名。

反之,当设置 name 属性之后, name 属性对应的值,就是 beanName。
而且,属性的值,可以有多个,每一个都是可以使用的。
但是!此时 方法名 就不可以使用了! 


 

2、获取 Bean 对象(对象装配)

获取 bean 对象也叫做 对象装配,是把对象取出来放到某个类中,有时候也叫 对象注⼊。

对象装配,简单来说:
就是在使用 A 的时候,需要用到 B了。
那么,你将 B 对象 注入到 A 里面来,让我来用。
因此,对象装配,又可以称为 对象注入。
更直白来说:对象装配(对象注入),就是将 bean 从 Spring 中取出来。

对象装配(对象注⼊)的实现⽅法以下 3 种:

1、 属性(字段)注⼊
2、 构造⽅法注⼊
3、 Setter 注⼊
接下来,我们分别来看。 


2.1 属性注入

2.1.1 @Autowired 注解 (Spring)

autowired 的意思就是自动装配

因此,可以得出结论:

在使用 @Autowired 进行 属性注入的时候
如果 注入的对象,被多次 存入 Spring 中了,那么,光凭 属性的类型是找不到匹配的 bean的!需要将 属性的变量名 改成 BeanName,根据 BeanName 来找寻匹配的对象(bean)并进行 属性注入。

方法不止这一种,但是上述这种 “精确描述 bean 的名称” 的方法,是最简单高效的!

是不是很简单,不用去获取 Spring 的上下文对象 和 getBean 方法,直接通过一个注解,即可获取对应的bean(从Spring中取出 bean)。 

属性注入的优点是:简单

属性注入的缺点主要包含以下三个:

1.功能性问题: 无法注入一个不可变的对象 (final 修饰的对象)
2. 兼容性问题: 只能适应于 loC 容器
3.设计原则问题:更容易违背单一设计原则


2.1.2  @Resource 注解  (JDK)

@Resource 注解,是来自于 JDK 的!【JDK 自带的注解】

而 @Autowired, 是属于 Spring的!
@Resource 注解 比 @Autowired 的 属性要强!
因为 @Resource 注解 有一个 name 属性,可以用指定 注入的 bean 的名称。

 但是问题来了!如果公司强制要求 使用 @Autowired,怎么办!?
其实还有第三种方法:


2.1.3 @Autowired 搭配 @Qualifier  注解

Qualifier - 限定符 :解决注入迷失问题的。
你可以将 @Qualifier 注解 认为是 一个筛选器。

我们不是通过@Autowired注解 获得了 User1,User2,两个 bean 嘛。
此时,我们就可以通过 @Qualifier 注解,对齐搜索结果,进行筛选!

那么,怎么去使用 @Qualifier 注解呢?
很简单!给 @Qualifier 一个参数(限定符 / beanName),根据 这个参数,对 @Autowired注解 查询的结果,进行筛选! 

 其实 @Qualifier 和 @Resource 的 name属性类似的!
为什么这么说?
因为 @Qualifier,其实调用了 自身的 value 属性。(隐式的调用 / 默认调用)

虽然 @Qualifier 的属性 可以省略。
但是!指不定 那次版本更新,就删除(或修改)了这一机制。
要求我们必须显式的 给 value 属性 赋值(或者,默认调用的属性,不再是 value了)。
因此,最好还是 显式 的 给 value 赋值。

通过 这种写法,我们的属性名可以随便取自己喜欢的名称。
不用去刻意的修改成 对应的beanName。


2.2 构造方法注入

还是使用 @Autowired 来注解来实现。

需要注意的是 @Resource 注解,是不支持 构造方法注入的!

 另外,在补充一个细节:

当 类里面只有一个构造方法的时候,@Autowired 是可以省略的!

优点:(官方推荐)

1.可注入不可变对象;

2.注入对象不会被修改;

3.注入对象会被完全初始化;

4.通用性更好。


2.3  Setter 注入

这个也是一样的,还是通过 @Autowired 实现 Setter 注入。

 另外,@Resource也支持 Setter 注入。

Setter的优点:符合单一设计原则(每个方法只传递一个对象)

缺点:1.不能注入不可变对象 (final 修饰的对象) ;2.注入的对象可被修改


拓展1:经典面试题 -> 属性注入 ,构造方法注入 和 Setter 注入 之间,有什么区别?

拓展2:@Resource VS @Autowired 的区别

1、用法不同

@Autowired,支持 属性注入,构造方法注入,Setter 方法注入。

@Resource:支持 属性注入,Setter方法注入。不支持 构造方法注入。

2、@Resource 的 属性注入 比 @Autowired 的 属性注入,使用的更舒服。 因为 @Resource 有很多的属性可以设置;而 @Autowired 只有一个 value 属性。

有很多的属性,即意味着可以使用很多其它的功能。

 比如: @Resource 的 name 属性,
那么,可以利用 name 属性可以用来指定 beanName,从而注入对应的 bean。

而 @Autowired 需要将属性变量名修改成对应的 beanName,才能获取对应的bean。
又或者,通过搭配 @Qualifier 注解 来获取对应的bean。
至于其它的,@Autowired 都没有属性了,还怎么对比。。
所以,关于 属性注入方面, @Resource 注解 更好用!

3、出身不同

@Autowired 是 Spring 框架 提供的。

@Resource 是 JDK 提供的。

这么说吧:
如果使用的是 @Resource,转移平台的时候(框架改变了),只要对方也是基于Java实现的,程序是能够使用的。

反之,如果使用的 @Autowired,它是只支持 spring 。
换了一个框架,就不可以用了。
庆幸的是:Spring 占据中国市场的份额,几乎是 100% !
因此,这个问题可以不用担心!
知道有这件事就行。


总结

1、将对象存储奥 Spring 中

1、使用五大类注解:@Controller,@Service,@Reposity,@Configuration,@Component【@Component 是 其余四大类注解的 “父” 级】

2、使用 方法注解 @Bean
【注意事项:@Bean 必须搭配五大类注解才能使用】

2、Bean的命名规则:

需要存入Spring中的类,其类名的第二个字母非大写,在没有指定 beanName 的情况下,默认生成的 beanName 是 类名的首字母小写 的状态(小驼峰)

反之,如果类名的 首字母 和 第二个字母 都是大写的,在没有指定 BeanName 的情况下,默认生成的 BeanName 就是 类的原名。

3、从 Spring 中获取对象

1、属性注入
  1.1、使用 @Autowired注解实现(属性的变量名 和 【bean id / bean name】 相同)

  1.2、使用 @Resource 注解 实现。(添加一个name 属性,其name的值是 bean id)

  1.3、使用 @Autowired 的同时,搭配 @Qualifier 注解。【通过 指定 @Qualifier 的 value 属性值(值为 bean id),】


2、Setter 注入

3、构造方注入 【官方推荐,但是它自己却用的很少】

4、注入的关键字有

1、@Autowired
2、@Resource

5、@Autowired 和 @Resource

1、出身不同【@Autowired 是 Spring 提供的,@Resource 是 JDK 提供的】
2、使用的属性不同【@Autowired 只有一个 value 属性,@Resource 除了name,还有很多】
3、用法不同
【@Autowired 支持 属性注入,构造方法注入,Setter 注入】
【@Resource 支持 属性注入,Setter 注入】

6、解决同一类型多个Bean的报错

1、使用 @Resource(name =“bean id”)
2、使用 @Autowired + @Qualifier(value=“bean id”) 

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

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

相关文章

Spring Boot|启动图案修改ASCII字符画

效果图 实现 在项目目录的resources文件夹中新建一个banner.txt&#xff0c;将内容放入即可&#xff1a; // _ooOoo_ // // o8888888o // // …

RHEL8.2安装QEMU及KVM虚拟化

一、环境 操作系统&#xff1a;CentOS8.2CPU&#xff1a;4C内存&#xff1a;16G磁盘&#xff1a;250G&#xff0c;其中180G分配给/data&#xff0c;用于存储数据及kvm存储池。 二、安装步骤 dnf module install virt dnf install virt-install virt-viewer virt-manager -y三…

Jenkins与CI/CD

简介 CI&#xff08;持续集成&#xff09; Continuous Integration是一种软件开发实践&#xff0c;即团队开发成员经常集成他们的工作&#xff0c;通常每个成员每天至少集成一次&#xff0c;也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建&#xff08;包括编…

监控摄像头的像素200万,400万,800万都是什么意思,200万像素、400万像素、800万像素是如何换算出来的?

一、像素 像素&#xff08;Pixel&#xff09;是用来表示图像分辨率的单位&#xff0c;数字越大&#xff0c;表示图像中的细节可以更精细地展现。当我们谈论监控摄像头的像素时&#xff0c;通常指的是摄像头图像传感器上的像素数量。像素的数量可以通过传感器上的横向像素数乘以…

【吴恩达deeplearning.ai】基于ChatGPT API打造应用系统(上)

以下内容均整理来自deeplearning.ai的同名课程 Location 课程访问地址 DLAI - Learning Platform Beta (deeplearning.ai) 一、大语言模型基础知识 本篇内容将围绕api接口的调用、token的介绍、定义角色场景 调用api接口 import os import openai import tiktoken from dote…

Java并发编程中的JMM、3个基本属性、synchronized和volatile

1、Java内存模型JMM (Java Meemory Model) JMM规定&#xff0c;所有变量均存储在主内存中每个线程都有自己的工作内存&#xff0c;保存了该线程中用到的变量的主内存副本拷贝线程对变量的所有操作&#xff0c;必须在自己的工作内存中&#xff0c;不可直接读写主内存不同线程无法…

【VsCode远程开发】Windows SSH远程连接Linux服务器 - 无公网IP内网穿透

文章目录 前言视频教程1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 转…

PostgreSql 逻辑结构

Database Cluser: 数据库集簇&#xff0c;一套服务器上安装部署完成的一套PostgreSql。在其中可创建数据库&#xff08;Database&#xff09;、用户&#xff08;User&#xff09;。User: 数据库用户&#xff0c;用来连接访问数据库&#xff0c;可通过权限管理&#xff0c;控制其…

Visual studio(VS)运行障碍指北

文章目录 VS: ....Microsoft.CppCommon.targets: error MSB6006: “CL.exe”已退出-VS2017许可证过期VS下Visual Assist X番茄插件安装失败子工程引用&#xff08;无法解析的外部符号&#xff09;无法打开.ui文件&#xff08;qt&#xff09;VS中qt子工程无法加载 VS: …Microso…

UE5《Electric Dreams》项目PCG技术解析 之 理解Assembly(以SplineExample为例)

文章目录 1. 什么是Assembly2. PCG部分2.1 Assembly变换2.2 Point变换2.2.1. SG_CopyPointsWithHierachy2.2.2 过滤及点变换2.2.3. ApplyHierachy 3. 小结 1. 什么是Assembly UE5.2的PCG出了有一段时间了&#xff0c;大家玩得都很开心。很多朋友可能和老王一样&#xff0c;使用…

docker学习(一)docker概述

Docker 是什么 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言&#xff0c;并遵从 Apache2.0 协议开源。它可以让开发者打包应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。Docker 可用于…

BeanShell:多线程环境下Interpreter解释器的优化使用

BeanShell是用 Java 编写的一个小型、免费、可嵌入的 Java 代码的脚本解释器。 BeanShell动态执行标准Java语法&#xff0c;并使用通用语法对其进行扩展 脚本编写便利性&#xff0c;适用于 Java 的轻量级脚本。本文说明在并发环境下对BeanShell更加优化的使用方式。 简单示例 …