Spring 的存储和获取Bean

news2025/1/17 21:32:28

文章目录

  • 获取 Spring 上下文对象的方式
  • 存储 Bean 对象的方式
    • 类注解
      • 配置扫描路径(必须)
      • @Controller(控制器存储)
      • @Service(服务)
      • @Repository(持久层)
      • @Component(工具)
      • @Configuration(项目中的一些配置)
      • 关于五大类注解
    • 方法注解
  • 获取指定的 Bean 对象的方式
    • 普通方式
    • 对象注入
      • 属性注入
      • 构造方法注入
      • Setter 注入
      • @Resource:另⼀种注入关键字
      • 总结

获取 Spring 上下文对象的方式

首先获取 Bean 对象之前都需要先获取 Spring 的上下文对象,那么获取这个对象可以有以下方式

ApplicationContext context =
		new ClassPathXmlApplicationContext("spring-config.xml");

BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));

那么这两者之间有什么区别呢,现在新建两个 Bean 类运行起来后看结果:

1、ApplicationContext

image-20240125172346756

2、BeanFactory

image-20240125172539215

两者的运行结果是不一样的,通过 BeanFactory 实例出来的并不会将 Teacher 对象放入 Spring

ApplicationContext 和 BeanFeactory:

  1. ApplicationContext 会将 xml文件中所声明需要注册到Spring中的 Bean 一次性全部注册完成,而BeanFactory 则是在首次去获取某一个Bean 对象时才会去注册该对象
  2. ApplicationContext 比较废内存但是之后的读取会很快
  3. BeanFeactory 比较省内存但是效率较低
  4. ApplicationContext 是 BeanFeactory 的子类,ApplicationContext 还拥有独特的特性, 添加了对国际化支持、资源访问支持、以及事件传播等方面的支持

存储 Bean 对象的方式

基本的存储方式需要在 spring-config.xml 文件中去添加指定的 Bean 注册内容才行,这样就很麻烦。

类注解

配置扫描路径(必须)

首先在进行注解前需要先配置好路径,在 spring-config.xml 中添加下面的代码

<content:component-scan base-package="spring.demo"></content:component-scan>

base-package中添加的是一串路径,也就是声明这个路径下的包中的 Bean 是有可能需要存入到 Spring 中的。注意只是有可能,开始的时候并没有立即注册存放到 Spring 中。

@Controller(控制器存储)

验证用户请求的数据正确性,相当于“安保系统”

Student类

import org.springframework.stereotype.Controller;

@Controller // 将当前类存储到 Spring 中
public class Student {
    public Student(){
        System.out.println("Student init");
    }

    public void print(String str){
        System.out.println(str);
    }
}

启动类

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring.demo.Student;

public class Start {
    public static void main(String[] args) {
        // 获取 Spring 的上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        // 获取 Bean 对象
        Student student = (Student) context.getBean("student", Student.class);
        // 使用 Bean 对象
        student.print("hello world");
    }
}

因为使用了注解后并没有指定id属性,这时需要将id属性写为类名的小驼峰形式,这是一个“约定”。

但是也有特例:

原类名如果首字母和第二个字母都是大写的话,id属性的名称就和原类名相同

@Service(服务)

编排和调度具体执行方法,相当于“客服中心”

Student类

@Service // 将当前类存储到 Spring 中
public class Student {
    public Student(){
        System.out.println("Student init");
    }

    public void print(String str){
        System.out.println(str);
    }
}

这样也同样可以执行程序

@Repository(持久层)

和数据库进行交互,是一个“执行者”(DAO)

Student类

@Repository // 将当前类存储到 Spring 中
public class Student {
    public Student(){
        System.out.println("Student init");
    }

    public void print(String str){
        System.out.println(str);
    }
}

这样也同样可以执行程序

@Component(工具)

主要是注解工具类

Student类

@Component // 将当前类存储到 Spring 中
public class Student {
    public Student(){
        System.out.println("Student init");
    }

    public void print(String str){
        System.out.println(str);
    }
}

这样也同样可以执行程序

@Configuration(项目中的一些配置)

Student类

@Configuration // 将当前类存储到 Spring 中
public class Student {
    public Student(){
        System.out.println("Student init");
    }

    public void print(String str){
        System.out.println(str);
    }
}

这样也同样可以执行程序

关于五大类注解

  1. 如果遇到同一个包中有 同名的类 那么可以在使用注解时使用例如 @Controller(value = “XXX”) 这种方式去分别,但是建议一个包中尽量不要有同名类
  2. 五大注解的关系:事实上五大注解都是基于 Component 实现的,也就是它们都是 Component 的“子类”,是对于 Component 的扩展。那么需要分出这么多类注解的原因就是让程序员看到类注解之后,就能直接了解当前类的用途

方法注解

方法注解就是在一个有返回值的方法上加上 @Bean 注解的方式,也就是说 Spring 会将有着 @Bean 注解的方法的返回值的对象存入

需要注意:

  1. @Bean 注解需要配合五大类注解使用
  2. 使用了@Bean 注解后,默认的 Bean 对象ID属性为该具有 @Bean 注解的方法名
  3. 可以使用 @Bean(name = {“XXX”})的形式去设置这个 Bean 对象的ID属性。并且这个重命名的 name 其实是⼀个数组,一个 Bean 可以有多个名字,例如 @Bean(name = {“XXX”, “XXX”})。并且 name= 是可以去掉的,例如 @Bean({“XXX”, “XXX”})
@Component
public class UserBeans {
    @Bean({"user"})
    public User getUser(){
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}
public class Start {
    public static void main(String[] args) {
        // 获取 Spring 的上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        // 获取 Bean 对象
        User user = context.getBean("user", User.class);
        // 使用 Bean 对象
        System.out.println(user.getName());
    }
}

image-20240126175928869

获取指定的 Bean 对象的方式

获取到上下文对象之后就可以通过调用该对象的 getBean方法去获取 Bean 对象

普通方式

首先常规的就是使用加载时设置的 id 属性去获取

Student student = (Student) context.getBean("student");

需要注意这种方式的返回值是 Object 类的,因此需要强转为 Bean 对象的类

第二种方式可以通过 Bean类的.class 加上 id 属性去获取

Student student = context.getBean("student", Student.class);

这样写法就比较优美

第三种方式可以直接通过 .class去获取,但是存在隐患

Student student = context.getBean(Student.class);

存在什么隐患呢,首先一个 Bean类是可以存放多个对象到 Spring 中的,也就是可以这样

<bean id="student" class="spring.demo.Student"></bean>
<bean id="student2" class="spring.demo.Student"></bean>

那么如果还使用第三种方式就会出现,编译器不知道具体是要获取哪一个对象,就会报错

image-20240125174238394

因此不建议使用这种方式

对象注入

在 Spring 中实现依赖注入的常见方式有以下 3 种:

  1. 属性注入(Field Injection);
  2. 构造方法注入(Constructor Injection);
  3. Setter 注入(Setter Injection)。

属性注入

属性注⼊是使⽤ @Autowired 实现的,例如下列代码

// UserService

@Service
public class UserService {
    public void print(){
        System.out.println("hello");
    }
}
// UserController

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    public void print(){
        userService.print();
    }
}
// Start

public class Start {
    public static void main(String[] args) {
        // 获取 Spring 的上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        // 获取 Bean 对象
        UserController user = context.getBean("userController", UserController.class);
        // 使用 Bean 对象
        user.print();
    }
}

image-20240126180319147

首先可以看到 UserService 和 UserController 这两个类都是加了类注解的,因此在程序运行后,这两个 Bean 都是会被存放到 Spring 中。因为在 UserController 类包含了一个 UserService 对象,并且加了 @Autowired 注解,所以这个 UserService 对象就不需要 new 出来,而是会自动从 Spring 中直接获取。这就是属性注入

属性注入的优点:

​ 属性注入最大的优点就是实现和使用简单,只需要给变量上添加一个 @Autowired 注解,就可以在不 new 对象的情况下直接获得注入的对象

属性注入的缺点:

  1. 无法注入一个不可变的对象,也就是final 修饰的对象
  2. 只能适应于 IoC 容器
  3. 更容易违背单一设计原则

构造方法注入

构造方法注入是在类的构造方法中实现注入

// UserService

@Service
public class UserService {
    public void print(){
        System.out.println("hello");
    }
}
// UserController

@Controller
public class UserController {
   private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void print(){
        userService.print();
    }
}
// Start

public class Start {
    public static void main(String[] args) {
        // 获取 Spring 的上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        // 获取 Bean 对象
        UserController user = context.getBean("userController", UserController.class);
        // 使用 Bean 对象
        user.print();
    }
}

image-20240126180319147

当该类中只有一个构造方法的时候,可以省略 @Autowired 注解,但是有多个构造方法时就需要在需要注入的方法上加上 @Autowired 注解

构造方法注入的优点:

  1. 可注入不可变对象;
  2. 注入对象不会被修改;(构造方法在对象创建时只会执行一次,因此它不存在注入对象被随时(调用)修改的情况
  3. 注入对象会被完全初始化;(注入的对象在使用之前会被完全初始化
  4. 通用性更好。(可适用于任何环境,无论是 IoC 框架还是非 IoC 框架

Setter 注入

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

// UserService

@Service
public class UserService {
    public void print(){
        System.out.println("hello");
    }
}
// UserController

@Controller
public class UserController {
   	private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void print(){
        userService.print();
    }
}
// Start

public class Start {
    public static void main(String[] args) {
        // 获取 Spring 的上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        // 获取 Bean 对象
        UserController user = context.getBean("userController", UserController.class);
        // 使用 Bean 对象
        user.print();
    }
}

image-20240126180319147

Setter注入的优点:

  1. 完全符合单一职责的设计原则,一个set方法只针对一个对象

Setter注入的缺点:

  1. 不能注入不可变对象;(final 修饰的对象)
  2. 注入的对象可被修改。(因为set方法的缘故,因此对象可以被随时随地修改)

@Resource:另⼀种注入关键字

@Controller
public class UserController {
    @Resource
    private UserService userService;

    public void print(){
        userService.print();
    }
}

@Autowired 和 @Resource 的区别:

  1. @Autowired 来自于 Spring,而 @Resource 来自于 JDK 的注解
  2. 相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如 name 设置,根据名称获取 Bean,可以使用@Resource(name=“XXX”) 指定获取。而 @Autowired 需要配合 @Qualifier(value = “XXX”)
  3. @Resource 只能用于 Setter 注入和属性注入,不能用于构造函数注入

总结

属性注入的写法最简单,所以日常项目中使用的频率最高,但它的通用性不好;

而 Spring 官方推荐的是构造方法注入,它可以注入不可变对象,其通用性也更好。

如果是注入可变对象,那么可以考虑使用 Setter 注入

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

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

相关文章

༺༽༾ཊ—Unity之-04-工厂方法模式—ཏ༿༼༻

首先创建一个项目&#xff0c; 在这个初始界面我们需要做一些准备工作&#xff0c; 建基础通用文件夹&#xff0c; 创建一个Plane 重置后 缩放100倍 加一个颜色&#xff0c; 任务&#xff1a;使用工厂方法模式 创建 飞船模型&#xff0c; 首先资源商店下载飞船模型&#xff0c…

【程序员英语】【美语从头学】初级篇(入门)(笔记)Lesson10(电话会话Ⅱ)

《美语从头学初级入门篇》 注意&#xff1a;被 删除线 划掉的不一定不正确&#xff0c;只是不是标准答案。 文章目录 Lesson 10 Telephone Conversation Ⅱ 电话会话&#xff08;二&#xff09;会话A会话B笔记I would like to do&#xff08;Id like to to do&#xff09;我想…

颠覆半导体:煤炭变身新材料,或将现身下一代CPU

《IEEE Spectrum》报道&#xff0c;一组研究人员正在探索将煤炭作为下一代二维晶体管绝缘材料的潜在替代品&#xff0c;以取代现有的金属氧化物薄膜。如果煤炭能够成功替代现代金属氧化物晶体管&#xff0c;那么这对于半导体行业来说将具有重大意义。 半导体器件正常工作需要依…

【数据结构和算法】--- 二叉树(5)--二叉树OJ题

目录 一、二叉树OJ题1.1 单值二叉树1.2 检查两颗树是否相同1.3 对称二叉树1.4 另一颗树的子树1.5 平衡二叉树 二、概念选择题 一、二叉树OJ题 1.1 单值二叉树 题目描述&#xff1a; 如果二叉树每个节点都具有相同的值&#xff0c;那么该二叉树就是单值二叉树。只有给定的树是…

AIGC知识速递——Google的Bert模型是如何fine-tuning的?

Look&#xff01;&#x1f440;我们的大模型商业化落地产品&#x1f4d6;更多AI资讯请&#x1f449;&#x1f3fe;关注Free三天集训营助教在线为您火热答疑&#x1f469;&#x1f3fc;‍&#x1f3eb; 选择合适的预训练模型&#xff1a; 从预训练的BERT模型开始&#xff0c;例如…

解决PyCharm的Terminal终端conda环境默认为base无法切换的问题

问题描述 在使用PyCharm的Terminal终端时&#xff0c;打开的默认环境为base。 在使用切换命令时&#xff0c;依旧无法解决。 解决方法 1、输入以下命令以查看conda的配置信息&#xff1a; conda config --show2、在输出中找到 auto_activate_base 的行&#xff0c;发现被…

【Linux 基础】常用基础指令(上)

文章目录 一、 创建新用户并设置密码二、ls指令ls指令基本概念ls指令的简写操作 三、pwd指令四、cd指令五、touch指令六、rm指令七、mkdir指令八、rmdir 指令 一、 创建新用户并设置密码 ls /home —— 查看存在多少用户 whoami —— 查看当前用户名 adduser 用户名 —— 创建新…

防御保护--第一次实验

目录 一&#xff0c;vlan的划分及在防火墙上创建单臂路由 二&#xff0c;创建安全区域 三&#xff0c;配置安全策略 四&#xff0c;配置认证策略 五&#xff0c;配置NAT策略 1.将内网中各个接口能够ping通自己的网关 2..生产区在工作时间内可以访问服务器区&#xff0c;仅…

解密人工智能:探索机器学习奥秘

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 机器学习的定义二. 机器学习的发展历程三. 机器学习的原理四. 机器学习的分类…

探索Pyecharts之美-绘制多彩旭日图的艺术与技巧【第37篇—python:旭日图】

文章目录 引言准备工作绘制基本旭日图调整颜色和样式添加交互功能定制标签和标签格式嵌套层级数据高级样式与自定义进阶主题&#xff1a;动态旭日图数据源扩展&#xff1a;外部JSON文件总结 引言 数据可视化在现代编程中扮演着重要的角色&#xff0c;而Pyecharts是Python中一个…

算法学习之位运算

一、作用 在复杂问题中经常可以作为工具让代码更加优雅。 二、知识储备基础 “~”&#xff1a;取反符 0->1, 1->0 三、常见的两种操作 1.n的二进制表示中第k位数字是几&#xff1f; (1)原理 先右移操作&#xff0c;再与操作。 &#xff08;2&#xff09;代码实现…

【C++杂货铺】详解类和对象 [上]

博主&#xff1a;代码菌-CSDN博客 专栏&#xff1a;C杂货铺_代码菌的博客-CSDN博客 目录 &#x1f308;前言&#x1f308; &#x1f4c1; 面向对象语言的特性 &#x1f4c1; 类 &#x1f4c2; 概念 &#x1f4c2; 定义 &#x1f4c1; 访问限定符 &#x1f4c2;分类 &#x…

第5章 (python深度学习——波斯美女)

第5章 深度学习用于计算机视觉 本章包括以下内容&#xff1a; 理解卷积神经网络&#xff08;convnet&#xff09; 使用数据增强来降低过拟合 使用预训练的卷积神经网络进行特征提取 微调预训练的卷积神经网络 将卷积神经网络学到的内容及其如何做出分类决策可视化 本章将…

线性代数--------学习总结

高斯消去法&#xff1a;对于任意的矩阵&#xff0c;总是能够利用倍加和行变换的方法变化成为阶梯形矩阵&#xff08;每一行第一个非零元叫做主元&#xff0c;他所在的列就叫做主列------每一行的主列都在他上方任意一行主列的右边&#xff09;和行简化阶梯矩阵&#xff08;主元…

C++ STL中list迭代器的实现

list 的模拟实现中&#xff0c;重难点在于迭代器功能的实现&#xff0c;因此本文只围绕 iterator 及 const_iterator 的设计进行介绍&#xff0c;其余如增删查改则不再赘述——在C语言的基础上&#xff0c;这些都非常简单。 与 string / vector 不同&#xff0c;list 的节点原生…

27移除元素(简单)-经典面试150题

题目描述 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出…

【高效开发工具系列】Java读取Html

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

计算机考试-软件设计师

文章目录 基础知识分析与设计结构化方法分析与设计基础知识实战法宝 数据库分析与设计基础知识实战法宝 真题练习09下-结构化分析09上-数据库分析 基础知识 分析与设计 整体分析&#xff1a; 1-4分值 15 或者 20 总分55 分 5-6 选做一题 15 总时间150分钟第一题 15分 15分…

【MAC】Multi-Level Monte Carlo Actor-Critic阅读笔记

基本思想&#xff1a; 利用多层次蒙特卡洛方法&#xff08;Multi-Level Monte Carlo&#xff0c;MLMC&#xff09;和Actor-Critic算法&#xff0c;解决平均奖励强化学习中的快速混合问题。 快速混合&#xff1f; 在强化学习中&#xff0c;当我们说一个策略"混合得快"…

绘制太极图 - 使用 PyQt

大家好&#xff01;今天我们将一起来探讨一下如何使用PyQt&#xff0c;这是一个强大的Python库&#xff0c;来绘制一个传统的太极图。这个图案代表着古老的阴阳哲学&#xff0c;而我们的代码将以大白话的方式向你揭示它的奥秘。 PyQt&#xff1a;是什么鬼&#xff1f; 首先&a…