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

news2025/1/13 11:55:19

更简单的读取和存储对象

  • 一. 存储 Bean 对象
    • 1. 前置工作:配置扫描路径
    • 2. 添加注解存储 Bean 对象
      • @Controller(控制器存储)
      • @Service(服务存储)
      • @Repository(仓库存储)
      • @Component(组件存储)
      • @Configuration(配置存储)
    • 3. 为什么要这么多类注解?
      • 类注解之间的关系
      • Bean 命名规则
    • 4. 方法注解 @Bean
      • 方法注解要配合类注解使用
      • 重命名 Bean
  • 二. 获取 Bean 对象(对象装配)
    • 1. 属性注入
    • 2. 构造方法注入
    • 3. Setter 注入
    • 4. 三种注入优缺点分析
    • 5. @Resource:另一种注入关键字
    • 6. 同一类型多个 @Bean 报错

在 Spring 中想要更简单的存储和读取对象的核⼼是使⽤注解。

一. 存储 Bean 对象

之前我们存储 Bean 时,需要在 spring-config 中添加⼀⾏ bean 注册内容才⾏:
在这里插入图片描述
⽽现在我们只需要⼀个注解就可以替代之前要写的⼀⾏配置,不过在开始存储对象之前,我们先要来点准备⼯作。

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.demo.example"></content:component-scan>
</beans>
<content:component-scan base-package="com.demo.example"></content:component-scan>

上面这行代码指明了组件的扫描路径。即使添加了注解,如果不是在配置的扫描包下的类对象,也是不能被存储到 Spring 中的。

2. 添加注解存储 Bean 对象

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

  1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration。
  2. ⽅法注解:@Bean。

@Controller(控制器存储)

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

@Service(服务存储)

@Service
public class UserService {
    public void sayHi(String name) {
        System.out.println("Hi," + name);
    }
}

@Repository(仓库存储)

@Repository
public class UserRepository {
    public void sayHi(String name) {
        System.out.println("Hi," + name);
    }
}

@Component(组件存储)

@Component
public class UserComponent {
    public void sayHi(String name) {
        System.out.println("Hi," + name);
    }
}

@Configuration(配置存储)

@Configuration
public class UserConfiguration {
    public void sayHi(String name) {
        System.out.println("Hi," + name);
    }
}

3. 为什么要这么多类注解?

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

就是为了让程序员看到类注解之后,就能直接了解当前类的⽤途,⽐如:

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

程序的⼯程分层,调⽤流程如下:

在这里插入图片描述

类注解之间的关系

查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:这些注解⾥⾯都有⼀个注解 @Component,说明它们本身就是属于 @Component 的 “子类”

Bean 命名规则

1. 对于类的第一个首字母大写,第二个小写,那么第一个首字母改为小写就是存到容器中的 Bean 的名字。

@Component
public class UserComponent {
    public void sayHi(String name) {
        System.out.println("Hi," + name);
    }
}
        UserComponent userComponent = (UserComponent) context.getBean("userComponent");

2. 其他所有情况都是原 Bean 的名字

@Component
public class JDBC {
    public void sayHi(String name) {
        System.out.println("Hi," + name);
    }
}
//        JDBC jdbc = (JDBC) context.getBean("jDBC"); // 获取不到
        JDBC jdbc = (JDBC) context.getBean("JDBC"); // 获取的到

4. 方法注解 @Bean

类注解是添加到某个类上的,⽽⽅法注解是放到某个⽅法上的

方法注解要配合类注解使用

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

只在方法上加 @Bean 注解是不起作用的, 要搭配类注解一起使用。

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

注意:获取 Bean 时使用对应的方法名获取

User user = (User) context.getBean("user1");

重命名 Bean

可以通过设置 name 属性给 Bean 对象进⾏重命名操作。

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

此时我们使⽤ u1 就可以获取到 User 对象了

        User user = (User) context.getBean("u1");
        System.out.println(user);

这个重命名的 name 其实是⼀个数组,⼀个 bean 可以有多个名字:

@Component
public class Users {
    @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;
    }

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

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

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

  1. 属性注⼊
  2. 构造⽅法注⼊
  3. Setter 注⼊

1. 属性注入

举个栗子:使⽤ @Autowired 将 Service 类注⼊到 Controller 类中。

@Controller
public class UserController {
    // 注⼊⽅法1:属性注⼊
    @Autowired
    private UserService userService;
    
    public User getUser(Integer id) {
        // 注入之后直接就可以使用
        return userService.getUser(id);
    }
}

2. 构造方法注入

@Controller
public class UserController2 {
    // 注⼊⽅法2:构造⽅法注⼊
    private UserService userService;

    @Autowired
    public UserController2(UserService userService) {
        this.userService = userService;
    }
    
    public User getUser(Integer id) {
        return userService.getUser(id);
    }
}

如果只有⼀个构造⽅法,那么 @Autowired 注解可以省略。

@Controller
public class UserController2 {
    // 注⼊⽅法2:构造⽅法注⼊
    private UserService userService;
    // 将 Autowired 省略了
    public UserController2(UserService userService) {
        this.userService = userService;
    }
    
    public User getUser(Integer id) {
        return userService.getUser(id);
    }
}

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

3. Setter 注入

Setter 注⼊和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加上 @Autowired 注解。

@Controller
public class UserController3 {
    // 注⼊⽅法3:Setter注⼊
    private UserService userService;
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void getUser(Integer id) {
        userService.sayHi("hello");
    }
}

4. 三种注入优缺点分析

  • 属性注⼊的优点是简洁,使⽤⽅便;
    缺点是只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,要是想自己 new 一下这个类的对象,那么相关的依赖无法完成注入。
    并且不能注入一个不可变的对象(一个 final 修饰的类),因为 Java 中一个 final 对象要么直接赋值要么在构造方法中赋值,不能注入。
    在这里插入图片描述

  • 构造⽅法注⼊是 Spring 推荐的注⼊⽅式,它的缺点是如果有多个注⼊会显得⽐较臃肿,它的优点
    可以注入不可变对象;
    注入的对象不可变,因为构造方法只随着累加载执行一次;
    通用性更好。

  • Setter ⽅式是 Spring 前期版本推荐的注⼊⽅式,但通⽤性不如构造⽅法,同样不能注入一个不可变的对象,同时注入的对象可以被修改,因为 Setter 注入只是使用一个普通的方法,其他类也可以多次调用这个方法。所以 Spring 现版本已经推荐使⽤构造⽅法注⼊的⽅式来进⾏类注⼊了。

@Controller
public class UserController3 {
    // 注⼊⽅法3:Setter注⼊
    private UserService userService;
    @Autowired
    public void setUserService1(UserService userService) {
        this.userService = userService;
    }

    public void getUser() {
        this.setUserService1(null);
        userService.sayHi("");
    }
}

5. @Resource:另一种注入关键字

在进⾏类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊

@Controller
public class UserController {
    // 注⼊
    @Resource
    private UserService userService;
    public User getUser(Integer id) {
        return userService.getUser(id);
    }
}

@Autowired 和 @Resource 的区别

  • 出身不同:@Autowired 来⾃于 Spring,⽽ @Resource 来⾃于 JDK 的注解;
  • 使⽤时设置的参数不同:相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如name 设置,根据名称获取 Bean。
  • @Autowired 可⽤于 Setter 注⼊、构造函数注⼊和属性注⼊,⽽ @Resource 只能⽤于 Setter 注⼊和属性注⼊,不能⽤于构造函数注⼊。

6. 同一类型多个 @Bean 报错

当出现以下多个 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;
    }
}

在另⼀个类中获取 User 对象

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

代码执行报错,报错的原因是,⾮唯⼀的 Bean 对象
在这里插入图片描述

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

  • 使⽤ @Resource(name=“user1”) 定义。
  • 使⽤ @Qualifier 注解定义名称。
  1. 使⽤ @Resource(name=“XXX”)
@Controller
class UserController4 {
    // 注⼊
    @Resource(name = "user1")
    private User user;
    public User getUser() {
        return user;
    }
}
  1. 使⽤ @Qualifier
@Controller
public class UserController4 {
    // 注⼊
    @Autowired
    @Qualifier(value = "user2")
    private User user;
    public User getUser() {
        return user;
    }
}

好啦! 以上就是对 Spring 更简单的读取和存储对象的讲解,希望能帮到你 !
评论区欢迎指正 !

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

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

相关文章

基于transformer的心脑血管心脏病疾病预测

视频讲解:基于transformer的心脑血管疾病预测 完整数据代码分享_哔哩哔哩_bilibili 数据展示: 完整代码: # pip install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple/ # pip install optuna -i https://pypi.tuna.tsinghua.edu.cn/simple/ import numpy as np …

C++ - 位图 - bitset 容器介绍

前言 之前的两篇博客已经完成 闭散列的开放地址法的哈希表 和 哈希桶基本实现&#xff0c;和对 unordered_set 和 unordered_map 的封装 &#xff1a;C - 封装 unordered_set 和 unordered_map - 哈希桶的迭代器实现_chihiro1122的博客-CSDN博客C - 开散列的拉链法&#xff08…

【JVM】运行时数据区(内存区域划分)详解

文章目录 前言一、JVM 运行时数据区1, 堆2, Java 虚拟机栈3, 本地方法栈4, 程序计数器5, 元数据区 / 方法区 二、内存异常问题1, 栈溢出2, 内存溢出3, 内存泄露 总结 前言 &#x1f4d5;各位读者好, 我是小陈, 这是我的个人主页 &#x1f4d7;小陈还在持续努力学习编程, 努力通…

【重拾C语言】三、分支程序设计(双分支和单分支程序设计、逻辑判断、多分支程序设计、枚举类型表示;典型例题:判断闰年和求一元二次方程根)

目录 前言 三、分支程序设计 3.1 判断成绩是否及格——双分支程序设计 3.2 成绩加上获奖信息—单分支程序设计 3.3 逻辑判断——布尔类型 3.4 获奖分等级——多分支程序设计 3.5 表示汽车种类——枚举类型 3.6 例题 3.6.1 例题——判断某个年份是否闰年 3.6.2 例题—…

SG Former论文学习笔记

超越SWin和CSWin Transformer的新模型 代码地址&#xff1a;https://github.com/OliverRensu/SG-Former 论文地址&#xff1a;https://arxiv.org/pdf/2308.12216.pdf ViT在各种视觉任务中虽然成功&#xff0c;但它的计算成本随着Token序列长度的增加呈二次增长&#xff0c;这在…

前端系列-1 HTML+JS+CSS基础

背景&#xff1a; 前端系列会收集碎片化的前端知识点&#xff0c;作为自己工作和学习时的字典&#xff0c;欢迎读者收藏和使用。 笔者是后端开发&#x1f636;前端涉猎不深&#xff0c;因此文章重在广度和实用&#xff0c;对原理和性能不会过多深究。 1.html 1.1 html5网页结…

软考中级—— 操作系统知识

进程管理 操作系统概述 操作系统的作用&#xff1a;通过资源管理提高计算机系统的效率&#xff1b;改善人机界面向用户提供友好的工作环境。 操作系统的特征&#xff1a;并发性、共享性、虚拟性、不确定性。 操作系统的功能&#xff1a;进程管理、存储管理、文件管理、设备…

654.最大二叉树

力扣题目地址(opens new window) 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给…

BIT-7文件操作和程序环境(16000字详解)

一&#xff1a;文件 1.1 文件指针 每个被使用的文件都在内存中开辟了一个相应的文件信息区&#xff0c;用来存放文件的相关信息&#xff08;如文件的名字&#xff0c;文件状态及文件当前的位置等&#xff09;。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明…

uniapp实现微信小程序隐私协议组件封装

uniapp实现微信小程序隐私协议组件封装。 <template><view class"diygw-modal basic" v-if"showPrivacy" :class"showPrivacy?show:" style"z-index: 1000000"><view class"diygw-dialog diygw-dialog-modal bas…

边缘计算网关

一、项目整体框架图 二、项目整体描述 边缘计算网关项目主要实现了智能家居场景和工业物联网场景下设备的数据采集和控制。 整个项目分为三大层&#xff1a;用户接口层、网关层、设备层。 其中用户层通过QT客户端、WEB界面及阿里云提供数据展示和用户接口。 网关使用虚拟机代替…

【网络安全-sqlmap】sqlmap以及几款自动化sql注入工具的详细使用过程,超详细,SQL注入【5】

一&#xff0c;sqlmap 工具的详细使用 kali系统自带这个工具&#xff0c;无需安装直接sqlmap 后面接参数使用 Windows上参照以下方法安装即可 1-1 工具下载 1-1-1 sqlmap下载 sqlmap 工具下载地址&#xff1a; GitHub - sqlmapproject/sqlmap: Automatic SQL injection a…

多线程基础篇(多线程案例)

文章目录 多线程案例1、单例模式1&#xff09;饿汉模式2&#xff09;懒汉模式3&#xff09;线程安全吗&#xff1f;&#xff1f;4&#xff09;解决懒汉模式线程安全问题5&#xff09;解决懒汉模式内存可见性问题 2、阻塞队列1) 阻塞队列是什么&#xff1f;2) 生产者消费者模型1…

大屏自适应容器组件-Vue3+TS

1.引言 在做数字大屏时&#xff0c;图表能跟着浏览器的尺寸自动变化&#xff0c;本文采用Vue3前端框架&#xff0c;采用TypeScript语言&#xff0c;封装了一个大屏自适应组件&#xff0c;将需要显示的图表放入组件的插槽中&#xff0c;就能实现自适应屏幕大小的效果。 2.实际…

mysql-binlog

1. 常用的binlog日志操作命令 1. 查看bin-log是否开启 show variables like log_%;2. 查看所有binlog日志列表 show master logs;3.查看master状态 show master status;4. 重置&#xff08;清空&#xff09;所有binlog日志 reset master;2. 查看binlog日志内容 1、使用mysqlb…

前端相关题目随笔

Vh虽然获取到了视口高度&#xff0c;但是vh会随着屏幕的、大小变化&#xff0c;所以当减去一个数字之后&#xff0c;就会显示错误。 生成id 如果没有设置id&#xff0c;则可以通过new Date.getTime()获取一个时间&#xff0c;作为一个单独的id&#xff0c;也可以通过下载uuid生…

竞赛选题 机器视觉人体跌倒检测系统 - opencv python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 机器视觉人体跌倒检测系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&…

想要精通算法和SQL的成长之路 - 二叉树的序列化和反序列化问题

想要精通算法和SQL的成长之路 - 二叉树的序列化和反序列化问题 前言一. 二叉树的层序遍历&#xff08;BFS&#xff09;二. 二叉树的序列化与反序列化2.1 序列化操作2.2 反序列化操作 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 二叉树的层序遍历&#xff08;BFS&#xf…

Redis学习笔记(下):持久化RDB、AOF+主从复制(薪火相传,反客为主,一主多从,哨兵模式)+Redis集群

十一、持久化RDB和AOF 持久化&#xff1a;将数据存入硬盘 11.1 RDB&#xff08;Redis Database&#xff09; RDB&#xff1a;在指定的时间间隔内将内存中的数据集快照写入磁盘&#xff0c;也就是行话讲的Snapshot快照&#xff0c;它恢复时是将快照文件直接读到内存里。 备份…

操作系统原理-习题汇总

临近毕业&#xff0c;整理一下过去各科习题及资料等&#xff0c;以下为操作系统原理的习题汇总&#xff0c;若需要查找题目&#xff0c;推荐CtrlF或commandF进行全篇快捷查找。 操作系统原理 作业第一次作业选择题简答题 第二次作业选择题简答题 第三次作业选择题简答题 第四次…