Spring系列3 -- 更简单的读取和存储对象

前言 

        上一篇章总结了,Spring的创建与使用,通过创建Maven项目配置Spring的环境依赖,创建Spring框架的项目,然后通过在Resource目录下创建Spring-config.xml配置文件,添加<bean></bean>标签将我们需要的bean对象注入到容器中,然后通过ApplicationContext获取Spring上下文,使用getBean()方法获取bean对象.

        最后提出了一个问题就是:当我们想注入到容器多个对象的时候,我们希望一个个的创建标签进行创建,因为这样的操作太繁琐而且代码冗余,所以针对上述问题,Spring提供了更加简单的注入对象的操作,就是通过使用注解来完成上述操作.

目录

前言 

1. 存储Bean对象

1.1 配置扫描路径

1.2 添加类注解

1.2.1 类注解的使用

1.2.2 为什么会有这么多类注解

1.2.3 类注解之间的关系

1.3 Bean对象的命名规则

1.4 方法注解@Bean

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

2.1 属性注入

2.2 构造方法注入

2.3 Setter注入

2.4 三种注入方式的优点与缺点

2.5 @Resource 另一种注入关键字

2.6  同⼀类型多个 @Bean 解决


1. 存储Bean对象

1.1 配置扫描路径

注意:想要将对象成功的存储到 Spring 中,我们需要配置⼀下存储对象的扫描包路径,只有被配置的包下的所有类,添加了注解才能被正确的识别并保存到 Spring 中。

在项目的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 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><content:component-scan base-package="com.bit.service"></content:component-scan>
</beans>

 

1.2 添加类注解

首先我们之前就接触过类注解

 上述的@WebServlet就是一个类注解

在Spring中想要将对象进行存储到Spring中,有两种注解类型可进行实现:

1. 类注解:@Controller @Service @Repository @Component @Configuration

分别对应:控制器, 服务,仓库,组件,配置文件

2. 方法注解:@Bean

1.2.1 类注解的使用

这里使用@Controller注解进行演示,其他四个类注解的使用方式都是一样的.

@Controller // 将对象存储到 Spring 中
public class UserController {public void sayHi(String name) {System.out.println("Hi," + name);}
}

此时我们先使⽤之前读取对象的⽅式来读取上⾯的 UserController 对象,如下代码所示:

public class Application {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context =new ClassPathXmlApplicationContext("springconfig.xml");// 2.得到 beanUserController userController = context.getBean("userController", UserController.class);// 3.调⽤ bean ⽅法userController.sayHi("lisi");}
}

1.2.2 为什么会有这么多类注解

既然功能是⼀样的,为什么需要这么多的类注解呢?

这和为什么每个省/市都有⾃⼰的⻋牌号是⼀样的?⽐如陕⻄的⻋牌号就是:陕X:XXXXXX,北京的⻋牌号:京X:XXXXXX,⼀样。为什么需要怎么多的类注解也是相同的原因,就是让程序员看到类注解之后,就能直接了解当前类的⽤途.

 

  • @Controller:表示的是业务逻辑层;
  • @Servie:服务层;
  • @Repository:持久层;
  • @Configuration:配置层。

 

1.2.3 类注解之间的关系

查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:

 其实这些注解里面都有⼀个注解 @Component,说明它们本身就是属于 @Component 的“子类”。

1.3 Bean对象的命名规则

当我们使用applicationContext进行获取上下文,然后通过上下文进行获取容器中的对象的时候,我们常用的就是传入两个参数:

参数一: Bean对象类名首字母小写

参数二: Bean对象的类对象.

我们平常使用的命名规则是大驼峰

如果我们⾸字⺟和第⼆个字⺟都是⼤写时,我们在使用上述的方法进行获取类对象的时候就不会获取成功.

 

这个时候,我们就要查询 Spring 关于 bean 存储时⽣成的命名规则了, 我们可以在 Idea 中使⽤搜索关键字“beanName”可以看到以下内容: 

 

 它使⽤的是 JDK Introspector 中的 decapitalize ⽅法,源码如下:

public static String decapitalize(String name) {if (name == null || name.length() == 0) {return name;}// 如果第⼀个字⺟和第⼆个字⺟都为⼤写的情况,是把 bean 的名字直接存储了if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&Character.isUpperCase(name.charAt(0))){return name;}// 否则就将⾸字⺟⼩写char chars[] = name.toCharArray();chars[0] = Character.toLowerCase(chars[0]);return new String(chars);
}

所以就是遇到首字母和第二个字母都是大写的时候,我们获取对象的时候,名字是不变的.

1.4 方法注解@Bean

类注解是添加到某个类上的,⽽⽅法注解是放到某个⽅法上的,如以下代码的实现:

@Component
public class Users {@Beanpublic User user1() {User user = new User();user.setId(1);user.setName("Java");return user;}
}

这里需要注意的是,使用方法注解一定要配合方法注解.(因为一个项目类已经是很多了,每个类的方法也很多,所以整个项目的方法就会特别多,所以我们就需要配和类注解进行使用)

方法注解,可以将返回的对象的名字进行修改,我们在使用方法的时候,可能会返回许多类型相同的对象,所以我们可以将这些返回的对象进行修改名字,以便在以后获取的时候更加的方便.代码如下:

@Component
public class Users {@Bean(name = {"u1"})public User user1() {User user = new User();user.setId(1);user.setName("Java");return user;}// 可以起多个名字@Bean(name = {"u1", "us1"})public User user1() {User user = new User();user.setId(1);user.setName("Java");return user;}// 省略name的写法@Bean({"u1", "us1"})public User user1() {User user = new User();user.setId(1);user.setName("Java");return user;}
}

获取方法返回的对象

class App {
public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");// 2.得到某个 beanUser user = context.getBean("u1", User.class);// 3.调⽤ bean ⽅法System.out.println(user);}
}

思考:使⽤ @Bean 注解并重命名,尝试使⽤原来的类名⾸字⺟⼩写是否能正确获取到对象?

答案:当给@Bean 设置了name属性之后,使用原方法名就获取不到对象了,只能使用别名进行获取.(起了小名,大名就不能用了(挺离谱的,但是要遵循规则))

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

获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注⼊。
对象装配(对象注⼊)的实现⽅法以下 3 种:

  • 1. 属性注入
  • 2. 构造方法注入
  • 3. Setter 注入

接下来,我们分别来看。

2.1 属性注入

属性注⼊是使⽤ @Autowired 实现的,将 Service 类注⼊到 Controller 类中。Service 类的实现代码如下:

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

 将StudentService 对象注入到Controller中

@Controller
public class StudentController {// 1.使用属性注入的方式获取Bean对象@Autowiredprivate StudentService studentService;  // 自动将标有Service注解studentService对象进行注入public void sayHi(){// 调用获取Bean对象Service的方法进行使用studentService.sayHi();}
}

测试属性注入

public static void main4(String[] args) {// 1.测试属性注入ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");StudentController studentController = context.getBean("studentController",StudentController.class);studentController.sayHi();
}

2.2 构造方法注入

@Controller
public class StudentController3 {private StudentService studentService;@Autowired// 当有一个构造方法的时候可以将@Autowired省略public StudentController3(StudentService studentService){this.studentService = studentService;}public void sayHi(){// 调用获取Bean对象Service的方法进行使用studentService.sayHi();}
}

注意事项:如果只有一个构造方法,那么可以将@Autowired进行省略.

但是如果类中有多个构造⽅法,那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法,否则程序会报错.

2.3 Setter注入

可以为注入的对象进行添加set和get方法,然后给set方法添加@AutoWired注解

@Controller
public class StudentController2 {private StudentService studentService;public void sayHi(){// 调用获取Bean对象Service的方法进行使用studentService.sayHi();}// 给私有成员变量设置Setter方法,并且加上@Autowired注解@Autowiredpublic void setStudentService(StudentService studentService) {this.studentService = studentService;}
}

2.4 三种注入方式的优点与缺点

优点缺点
属性注入使用便捷

1.功能性:不能注入一个final修饰的对象

2.通用性:只适用于IOC容器中

3.设计原则: 容易违背单一设计原则(使用简单,犯错率大)

构造方法注入相对更符合单一设计原则

1. 不能注入不可变对象

2. 注入的对象随时可以被改变

setter方法注入使用相对复杂

1.可注入不可变对象

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

3.注入的对象可完全被初识化

4.通用性更好

2.5 @Resource 另一种注入关键字

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

@Controller
public class StudentController4 {@Resource(name = "student1")private Student student;
}

@Autowired 和 @Resource 的区别

  • 出身不同:@Autowired 来自于Spring,而@Resource 来自于JDK 的注解;
  • 使用时设置的参数不同:相比于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如name 设置,根据名称获取 Bean。
  • @Autowired 可⽤于 Setter 注入、构造函数注⼊和属性注入,而@Resource 只能用于Setter 注入和属性注入,不能⽤于构造函数注入。
  • 获取的Bean对象的顺序不同:autowired先根据名字在根据类型,Resource先根据类型再根据名字进行获取。

2.6  同⼀类型多个 @Bean 解决

@Component
public class Users {@Beanpublic User user1() {User user = new User();user.setId(1);user.setName("Java");return user;}@Beanpublic User user2() {User user = new User();user.setId(2);user.setName("MySQL");return user;}
}
@Controller
public class UserController4 {// 注⼊@Resourceprivate User user;public User getUser() {return user;}
}

 报错的原因是,⾮唯⼀的 Bean 对象。

解决同⼀个类型,多个 bean 的解决⽅案有以下两个:

  1. 使⽤ @Resource(name="user1") 定义。
  2. 使⽤ @Qualifier 注解定义名称。

① 使⽤ @Resource(name="XXX") 

@Controller
public class UserController4 {// 注⼊@Resource(name = "user1")private User user;public User getUser() {return user;}
}

 ② 使⽤ @Qualifier

@Controller
public class UserController4 {// 注⼊@AutoWired@Qualifier(value = "user2")private User user;public User getUser() {return user;}
}

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

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

相关文章

web服务端接收多用户并发上传同一文件,保证文件副本只存在一份(附go语言实现)

背景 对于一个文件服务器来说&#xff0c;对于同一文件&#xff0c;应该只保存一份在服务器上。基于这个原则&#xff0c;引发出本篇内容。 本篇仅阐述文件服务器在同一时间接收同一文件的并发问题&#xff0c;这种对于小体量的服务来说并不常见&#xff0c;但是最好还是要留…

文本分析-使用Python做词频统计分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

【滑动窗口】209. 长度最小的子数组

209. 长度最小的子数组 解题思路 滑动窗口设置前后指针滑动窗口内的元素之和总是大于或者等于s滑动窗口的起始位置: 如果窗口的值大于等于s 窗口向前移动窗口结束位置:for循环的j class Solution {public int minSubArrayLen(int target, int[] nums) {int left 0;// 滑动窗口…

学习系统编程No.28【多线程概念实战】

引言&#xff1a; 北京时间&#xff1a;2023/6/29/15:33&#xff0c;刚刚更新完博客&#xff0c;目前没什么状态&#xff0c;不好趁热打铁&#xff0c;需要去睡一会会&#xff0c;昨天睡的有点迟&#xff0c;然后忘记把7点到8点30之间的4个闹钟关掉了&#xff0c;恶心了我自己…

使用 Rust 实现连接远程 Linux 服务器、发送文件、执行命令

使用 Rust 实现连接远程 Linux 服务器、发送文件、执行命令 文章目录 使用 Rust 实现连接远程 Linux 服务器、发送文件、执行命令一、Rust 概述使用场景优点缺点 二、功能实现1、代码2、运行日志3、服务器文件 一、Rust 概述 Rust 已经听了无数遍&#xff0c;我很清楚它很强&am…

LVS-DR集群

目录 一、构建LVS-DR集群的步骤 实验环境准备&#xff1a; 1、配置负载调度器&#xff08;192.168.40.200&#xff09; 1.1 配置虚拟 IP 地址&#xff08;VIP&#xff1a;192.168.40.190&#xff09; 1.2 调整 proc 响应参数 1.3 配置负载分配策略 2. 部署共享存储&#xf…

Elasticsearch 基本使用(五)查询条件匹配方式(query query_string)

查询条件匹配方式 概述querytermtermsrangematch_allmatchmatch 匹配精度问题 match_phrasematch_pharse_prefixmatch_bool_prefixmulti_match query_string简单查询一个字段在多个字段上应用同一个条件 &#xff08;类似multi_match&#xff09;在所有字段上应用同一个条件 &a…

html掉落本地图片效果

实现一个加载本地图片并掉落的html页面。 说明 将DuanWu.html与zongzi_1.png, zongzi_2.png, zongzi_3.png, yadan.png4张图片放在同一个目录下&#xff0c;然后双击打开DuanWu.html即可。 使用Chrome或Microsoft Edge浏览器打开 若使用IE浏览器打开&#xff0c;下方会出现In…

什么是敏捷测试?

目录 前言&#xff1a; 敏捷测试的定义 敏捷测试的特点 为什么要敏捷测试 缩短价值交付周期 强调质量属于大家 化繁为简节省成本 敏捷测试VS. 传统测试 传统测试如何迁移到敏捷测试 1. 组织文化的转变 2. 组织架构的调整 3. 人员培训与指导 4. 轻流程 敏捷测试成…

一文了解潜力黑马Infiblue:借力Web3,释放元宇宙价值

2013 年&#xff0c;JDN Dionisio 曾发表了一篇名为《3D Virtual Worlds and the Metaverse: Current Status and Future Possibilities》的论文&#xff0c;深入探讨与归纳了虚拟世界的几个发展阶段&#xff0c;可以简单的归纳为&#xff1a; 第一阶段&#xff1a;基于计算机…

Blender基础入门(2):Blender简单渲染

文章目录 我个人的Blender专栏前言渲染基本常识科普Blender渲染设置Blender窗口分栏分屏渲染 渲染设置GPU渲染引擎推荐最大采样 切换摄像机渲染图片渲染采样512和4096差异512采样4096采样 渲染建议 我个人的Blender专栏 Blender简单教学 前言 渲染是从白模到成品的过程&…

CEC2018动态多目标优化算法:基于自适应启动策略的混合交叉动态约束多目标优化算法(MC-DCMOEA)求解CEC2018

一、动态多目标优化问题 1.1问题定义 1.2 动态支配关系定义 二、 基于自适应启动策略的混合交叉动态多目标优化算法 基于自适应启动策略的混合交叉动态多目标优化算法&#xff08;Mixture Crossover Dynamic Constrained Multi-objective Evolutionary Algorithm Based on Se…