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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security 是一个用于身份验证和授权的框架,它的源码读取顺序可以大致分为以下几个步骤: 1. 加载配置文件:Spring Security 使用 XML 或 Java Config 的方式进行配置,首先会加载配置文件,获取安全配置的相关信息。 2. 创建过滤器链:Spring Security 通过过滤器链来处理请求,根据配置文件中的顺序,创建不同的过滤器,并将它们按照一定的顺序组成过滤器链。 3. 加载认证信息:在过滤器链中,有一个特殊的过滤器称为 `UsernamePasswordAuthenticationFilter`,它负责处理用户名密码的认证。在请求到达该过滤器时,会根据配置的认证方式加载用户信息,例如从数据库或者内存中加载用户信息。 4. 执行认证逻辑:在认证过滤器中,会调用相应的 `AuthenticationManager` 进行认证。`AuthenticationManager` 是一个接口,具体的实现类是 `ProviderManager`,它会根据配置中的认证提供者(`AuthenticationProvider`)来进行认证操作。 5. 认证结果处理:认证完成后,会根据认证结果进行相应的处理。例如,如果认证成功,会生成一个身份验证凭证(`Authentication`)对象,并将其保存到 `SecurityContextHolder` 中,供后续的授权操作使用。 6. 执行授权逻辑:在过滤器链中,有一个称为 `FilterSecurityInterceptor` 的过滤器,它负责处理授权逻辑。当请求到达该过滤器时,会根据配置的访问规则进行权限检查,并决定是否允许请求进入。 7. 异常处理:在整个过程中,如果发生异常,Spring Security 会根据配置的异常处理机制进行相应的处理,例如重定向到登录页面或返回错误信息。 这只是 Spring Security 源码的一个简要读取顺序,具体的实现细节和流程会加复杂,涉及到很多不同的类和接口。如果你想深入了解 Spring Security 的源码,建议阅读官方文档以及相关的源码注释和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值