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

news2024/11/18 1:48:40

前言 

        上一篇章总结了,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.得到 bean
        UserController 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 {
    @Bean
    public 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.得到某个 bean
        User 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对象
    @Autowired
    private 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注解
    @Autowired
    public 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 {
    @Bean
    public User user1() {
        User user = new User();
        user.setId(1);
        user.setName("Java");
        return user;
    }
    @Bean
    public User user2() {
        User user = new User();
        user.setId(2);
        user.setName("MySQL");
        return user;
    }
}
@Controller
public class UserController4 {
    // 注⼊
    @Resource
    private 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.coloradmin.cn/o/730127.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mybatis-puls——条件查询的三种格式+条件查询null判定+查询投影

前言 在mybatis_plus的封装中的Wrapper<T>接口参数就是用于封装查询条件 在测试类中启动如上一个简单的查询&#xff0c;然后控制台运行会输出一大堆无关日志&#xff0c;这里先把这些日志关闭 去除无关日志文件 先新建一个XML配置文件 然后变成如下&#xff0c;这里…

[神经网络]YoloV7

Yolo系列是一类很经典的目标检测网络&#xff0c;属于anchor-base型网络&#xff0c;即需要先产生先验框然后筛选先验框得到预测框。同时它也是One-Stage网络&#xff0c;即不需要额外的网络结构来筛选先验框。这两种特点使得它具备了运算速度快和计算精度相对较高的特点。 比较…

Win10怎么用U盘重装系统?Win10用U盘重装系统步骤图解教程

Win10怎么用U盘重装系统&#xff1f;使用U盘重装系统是一种快速而有效的方法&#xff0c;可以帮助我们在电脑中进行Win10系统的重新安装。首先用户需要准备一个容量适当的U盘&#xff0c;并确保其中没有重要数据&#xff0c;然后按照小编分享的Win10用U盘重装系统步骤图解教程操…

Redis 简单入门

✏️作者&#xff1a;银河罐头 &#x1f4cb;系列专栏&#xff1a;JavaEE &#x1f332;“种一棵树最好的时间是十年前&#xff0c;其次是现在” 目录 安装 Redisredis 的数据类型和使用字符串类型字典类型列表类型集合类型有序集合类型 SpringBoot 集成 Redis添加 redis 依赖配…

el-checkbox / el-checkbox-group中绑定对象无法回显的问题处理

在使用el-checkbox / el-checkbox-group时&#xff0c;发现若label绑定的是对象&#xff0c;则是无法回显的&#xff0c;参考了很多方法&#xff0c;但大多都无法解决&#xff0c;最终参考下面的方法解决&#xff0c;记录一下。 <el-checkbox :label"JSON.stringify(i…

每天一点Python——day51

#第五十一天列表和字典为可变序列&#xff0c;元组是不可变序列 为什么要将元组设计成不可变序列呢&#xff1f; 一旦创建了不可变类型的对象&#xff0c;对象内部的所有数据将不能被修改 这样就避免了由于修改数据而导致的错误 对于不可变对象&#xff0c;在多任务环境下&…

最小覆盖串双指针解题思路及Java实现

最小覆盖串双指针解题思路及Java实现 题目双指针思路Java实现 题目 题目来自牛客NC28 最小覆盖子串 给出两个字符串 s 和 t&#xff0c;要求在 s 中找出最短的包含 t 中所有字符的连续子串。 例如&#xff1a; 输入&#xff1a;“XDOYEZODEYXNZ”,“XYZ” 返回值&#xff1a;“…

使用LiteSpeed缓存插件将WordPress优化到100%的得分

页面速度优化应该是每个网站所有者的首要任务&#xff0c;因为它直接影响WordPress SEO。此外&#xff0c;网站加载的时间越长&#xff0c;其跳出率就越高。这可能会阻止您产生转化并为您的网站带来流量。 使用正确的工具和配置&#xff0c;缓存您的网站可以显着提高其性能。因…

c++——命名空间

1.什么是命名空间 1.1命名空间的定义 命名空间&#xff08;Namespace&#xff09;是C中用来避免命名冲突的一种机制。命名空间可以将一组相关的函数、类、变量等定义在同一个逻辑分组中&#xff0c;从而避免它们与其他代码中的同名实体发生冲突。 C中&#xff0c;命名空间使用…

Openlayers实战:回显点、线段、圆形、多边形

Openlayers地图中,回显数据到地图上,形成几何图形是非常重要的一部分学习内容。 回显的内容基本单元包括点、线、圆形、多边形。本实战项目中,根据给定的坐标点,用最基础最管用的方式来显示这些信息。 效果图 源代码 /* * @Author: 大剑师兰特(xiaozhuanlan),还是大剑…

Keil环境下CANopenNode移植到STM32问题记录(一)---printf重定向问题

文章目录 问题描述问题结决思考&#xff1a;相关文章 在直接将CANopenSTM32的示例工程直接移植到Keil环境下。 如果移植工程未实现printf函数重定向&#xff0c;则要注释掉log_printf下面的printf函数&#xff0c;使日志打印失效 /* Printf function of CanOpen app */ #define…

Django_环境配置(一)

目录 一、安装Django 二、创建项目 三、创建应用 四、注册应用 五、使用mysql数据库 六、视图 七、开发服务器 源码等资料获取方法 一、安装Django # 在CMD中运行 pip install django # 查看djangp版本 python manage.py version 二、创建项目 # 在CMD中运行 django-a…

工业物联网安全监测解决方案:工业安全节能管理

工业自动化和工业化的快速发展&#xff0c;工厂安全问题越来越受到重视。工厂安全监测是保障工厂安全运行的关键技术之一&#xff0c;它可以及时发现并处理潜在的安全问题&#xff0c;防止事故的发生&#xff0c;保障员工的安全和工厂的正常运转。智能改造成为广大企业关注的热…

idea配置本地maven保姆级教程

一、说在前面 idea默认会带有maven插件&#xff0c;原则上是可以不需要配置的。但有个缺点&#xff0c;他是把本地仓库直接安装在了系统盘里面&#xff0c;随着时间的推移&#xff0c;仓库越来越大&#xff0c;笔记本的压力会比较大。 本文是下载自己的maven包&#xff0c;集…

DAY41:动态规划(一)动态规划理论基础

文章目录 DP概念以及和贪心的区别动规问题分类基础问题背包问题打家劫舍股票问题子序列问题 DP注意点解题步骤&#xff1a;五步debug考虑方向 视频课程&#xff1a;从此再也不怕动态规划了&#xff0c;动态规划解题方法论大曝光 &#xff01;| 理论基础 |力扣刷题总结| 动态规划…

3.1.cuda运行API-概述

目录 前言1. Runtime API概述总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习精简 CUDA 教程-Runtime API 概述 课程大纲可…

MachineLearningWu_3_LinearRegression

3 Linear Regression Linear Regression即是根据数据做出预测&#xff0c;如下&#xff0c; training set 如下&#xff1a; 在Linear Regression中你可以将(x&#xff0c; y)看做如下&#xff0c;每一行是一个sample&#xff0c;而每一列除最后一列是一个feature&#xff0c…

ESP32(掌控板) RGB灯控制

ESP32&#xff08;掌控板&#xff09; RGB灯控制 本程序实现了RGB灯亮度和颜色调节&#xff0c;通过触摸按键分别调节RGB值&#xff0c;通过机械按键选择要调节的灯或使用预设均通过调整变量的值加上判断实现。预设包含随机颜色和流水灯&#xff0c;各有高亮度和低亮度两种版本…

《Kali渗透基础》07. 弱点扫描(一)

kali渗透 1&#xff1a;漏洞发现1.1&#xff1a;Exploit-DB1.2&#xff1a;searchsploit1.3&#xff1a;nmap 2&#xff1a;漏洞管理3&#xff1a;弱点扫描类型4&#xff1a;漏洞基本概念4.1&#xff1a;CVSS4.2&#xff1a;CVE4.3&#xff1a;OVAL4.4&#xff1a;CCE4.5&#…

TCP概念

文章目录 1.TCP1.1 为什么需要 TCP 协议&#xff1f;TCP 工作在哪一层&#xff1f;1.2 什么是 TCP &#xff1f;1.3 什么是 TCP 连接&#xff1f;1.4 如何唯一确定一个 TCP 连接&#xff1f;1.5 有一个 IP 的服务器监听了一个端口&#xff0c;它的 TCP 的最大连接数是多少&…