• javaEE进阶 - Spring 更简单的读取和存储对象 - 细节狂魔


    文章目录

    前言

    经过前的 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 中。
    就是一开始进入项目,显示页面文件
    在这里插入图片描述

    
       
            org.springframework
            spring-context
            5.2.3.RELEASE
        
      
        
            org.springframework
            spring-beans
            5.2.3.RELEASE
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    如果引入失败,坑是没有使用国内源。
    你们可以 去看这篇文章 Spring 创建 和 使?,里面讲的很清楚

    在resources 目录下,创建一个 spring-config.xml 的配置文件。
    我们配置扫描路径,就是在这里配置的。

    将我们下面给的 配置内容,拷贝我们创建的 配置文件中。
    在这里插入图片描述

    准备工作,到此就结束!
    下面,我们就可以开始尝试:使用更简单的方式(使用注解) 来 存储/取出 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、使用 5 大类注解实现将 bean 存储到 容器

    @Controller 注解

    为了验证 注解 的 效果,我们先来在 beans 目录中,创建一个 User 类。
    在这里插入图片描述

    前面不是说:想要 bean 存入到 Spring中,需要满足2个条件:
    1、创建的 诶 需要在 根目录底下
    2、加上 五大类注解中的任意一个
    x现在,我们就来破坏条件2。
    看看 是否 代码 无法执行?在这里插入图片描述
    不难得出结论1:注解不可省略。

    再看看,不处于根目录下,会是什么样的效果。
    在这里插入图片描述
    由此,不难得出结论:
    要存入 Spring 中的 bean,必须处于 根目录下,而且注解不可省略!


    思考一个问题

    为什么?我们的 Spring 一定要有下面这个配置呢?
    在这里插入图片描述
    如果没有这个配置,意味着什么??

    大家可以想象一下:
    一个 Spring 项目中,我们的类可分两种类型:
    1、需要 进行 控制反转的类,将类的“生命周期”交给 Spring 来管理的类。【比如:UserController】

    2、不需要存入 Spring 中的 类。

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

    再思考一个问题:
    如果 根目录“beans”下面,还有子目录b。
    我们将 UserController 类 存放到 b 中,会不会被加载呢?在这里插入图片描述


    @Service

    还是一样的配方!
    在这里插入图片描述


    @Repository

    在这里插入图片描述


    @Configuration

    在这里插入图片描述


    @Component

    在这里插入图片描述


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

    这就涉及到 软件工程方面的知识了!
    在这里插入图片描述
    之所以讲这个 关于“软件分层” 的定义呢,就是为了 后面讲解 “为什么要有五大注解类” 做铺垫!
    在这里插入图片描述
    那么,问题来了,为什么不直接弄一个 “集大成者” 的注解呢?
    一个注解当五个用!

    这和为什么每个省/市都有的牌号是样的!
    如:
    陕的牌号就是:陕X:XXXXXX
    北京的牌号:京X:XXXXXX,样。
    甚个省不同的县区也是不同的,

    安就是,陕A:XXXXX,咸阳:陕B:XXXXXX,宝鸡,陕C:XXXXXX,样。
    这样做的好处除了可以节约号码之外,更重要的作是可以直观的标识辆的归属地。

    拓展一下:还有一个好处!
    不知道你们清不清楚,反正我记得 有些城市的道路,在某些特定时间,只允许本地车辆通行。这就起到了一个限流的作用。
    而且,对于现在我们国家正处于疫情阶段,车牌号 能帮助 判断 车辆是否 是从 高中风险 地区过来的,方便进行隔离。

    如果中国车辆的车牌,都是 中xxxxx
    那我们如何进行分别 车辆 的来源?
    那就只能几个人坐在电脑前,一个规格车牌进行输入查询。
    这就很麻烦!!!
    明明 第风险区 和 本地 不用盘查,现在却要都进行盘查。

    五大类注解,就是为了避免 混淆的情况出现,所以针对 类的不同场景,进行分层。每个注解负责的层次,是不一样的。
    但是只需要处理 各自负责的事务,就可以了。
    这就能提高执行的效率。

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

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

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

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

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

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


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

    这五个类注解实现的功能 都是一样的,只是“长得”不一样。
    那么,这 五个类注解之间,有什么关系呢?在这里插入图片描述
    结论:
    Component 注解,与其它四大注解,呈 “父子” 关系。

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


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

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

    但是!这一块有一个特例!!
    在这里插入图片描述
    总之,随你!
    看哪个都行!【建议下载下来,用idea 看,更舒服!】
    在这里插入图片描述
    验证一下:
    在这里插入图片描述
    到这里,我们就明白了 bean 的命名规则。
    但是!最好还是 不要斜侧 APIController 这种形式。
    虽然能执行,但是不符合规范。
    最好,还是写 UserController 这种。
    生成的 bean Name 是 小驼峰,才是“正统”!


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

    在这里插入图片描述

    同时,我有验证了一下 beanName,发现和 beanName 是没有关系的!在这里插入图片描述
    就是因为 @Bean 注解,需要搭配五大类注解 来使用。

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


    重命名 Bean

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

    而且,相信大部分朋友,可能都喜欢 将其命名为 getUser.
    在这里插入图片描述
    又或者是通过某种条件,来获取对象。
    比如:name 和 id,即 getUserByName,getUserById ,这种命名方式。
    相信是部分朋友的“习惯”。

    虽然这么命名,也能获取到对象。在这里插入图片描述
    这么说吧:我们 想要获取的是 bean,你填一个 方法名,好像有点不太合适吧?
    难道我们就不能使用 像类名的 命名规则 给 方法 重命名吗?
    答案:有的!!!
    在这里插入图片描述
    这里需要注意一点: 如果方法被重命名,原先的方法名,就没用了!
    换个说法:就是无法通过方法名,来获取 bean 了!
    在这里插入图片描述

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

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


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

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

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

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

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


    1、属性注入

    使 @Autowired 实现 属性注入。

    在这里插入图片描述

    在这里插入图片描述
    因此,可以得出结论:

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

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

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


    使用 @Resource 注解 进行 属性注入

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

    而 @Autowired, 是属于 Spring的!
    @Resource 注解 比 @Autowired 的 属性要强!
    因为 @Resource 注解 有一个 name 属性,可以用指定 注入的 bean 的名称。
    在这里插入图片描述
    但是问题来了!如果公司强制要求 使用 @Autowired,怎么办!?
    你也不知道是那个老六,闲的没事,注入一个,甚至几个相同的bean。
    取的名字又龊!都不想用,怎么办?
    其实还有第三种方法:
    @Autowired 注解, 搭配使用 @Qualifier 注解


    @Autowired注解,搭配使用 @Qualifier 注解,实现属性注入

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

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

    那么,怎么去使用 @Qualifier 注解呢?
    很简单!给 @Qualifier 一个参数(限定符 / beanName),根据 这个参数,对 @Autowired注解 查询的结果,进行筛选!在这里插入图片描述
    其实 @Qualifier 和 @Resource 的 name属性类似的!
    为什么这么说?
    因为 @Qualifier,其实调用了 自身的 value 属性。(隐式的调用 / 默认调用)
    在这里插入图片描述
    虽然 @Qualifier 的属性 可以省略。
    但是!指不定 那次版本更新,就删除(或修改)了这一机制。
    要求我们必须显式的 给 value 属性 赋值(或者,默认调用的属性,不再是 value了)。
    因此,最好还是 显式 的 给 value 赋值。

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


    总结

    对象注入的方法有三种

    1、精确描述 bean 的 名称(注入的名称要写对)
    2、使用 @Resource 来进行注入。
    3、@ Autowired注解,搭配使用 @Qualifier 注解


    2、 构造方法注入

    还是使用 @Autowired 来注解来实现。
    在这里插入图片描述
    需要注意的是 @Resource 注解,是不支持 构造方法注入的!
    在这里插入图片描述

    另外,在补充一个细节:

    当 类里面只有一个构造方法的时候,@Autowired 是可以省略的!
    在这里插入图片描述


    3、 Setter 注入

    这个也是一样的,还是通过 @Autowired 实现 Setter 注入。
    在这里插入图片描述
    另外,@Resource也支持 Setter 注入。
    在这里插入图片描述


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

    在这里插入图片描述


    @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”)

  • 相关阅读:
    OceanBase 数据库入门知识
    b站江科大stm32笔记(持续更新)
    K线形态识别_空方尖兵
    Proteus下仿真AT89C51单片机串行口的问题
    QT计时器QTime的使用举例
    使用 JMeter 和 Docker 进行服务存根
    awk运用三维数组进行插值获得任意经纬度处的水层沉积层地壳厚度
    你了解Java中的并发编程吗?
    21天经典算法之折半插入排序
    将时间序列转成图像——小波变换方法 Matlab实现
  • 原文地址:https://blog.csdn.net/m0_67401660/article/details/126019477