Spring 的存储和获取Bean

文章目录

  • 获取 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 注入

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Spring】Spring简介、IOC、DI

目录 Spring简介 Spring Framework五大功能模块 IOC容器 IOC思想 IOC容器在Spring中的实现 基于XML管理bean 配置bean 获取bean 依赖注入之setter注入 依赖注入之构造器注入 特殊值处理 字面量赋值 null值 xml实体 CDATA节 为类类型属性赋值 为数组类型属性赋值 为集合类型属性…

JavaScript 学习笔记(JS进阶 Day1)

「写在前面」 本文为 b 站黑马程序员 pink 老师 JavaScript 教程的学习笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. JavaScript 学习笔记&#xff08;Day1&#xff09; 2. JavaSc…

适用于 Windows 11 的 12 个最佳免费 PDF 编辑器

除了绘图等基本功能外&#xff0c;一些适用于 Windows 11 的免费 PDF 编辑器还具有 AI、OCR 识别和书签等高级功能。 我们的列表包含易于立即下载的 PDF 编辑软件工具。 这些工具不仅可以帮助转换 PDF、编辑、上传、删除、裁剪、分割、提取等。 PDF 是指便携式文档格式&…

单片机学习笔记---独立按键控制LED亮灭

直接进入正题&#xff01; 今天开始我们要学习一个新的模块&#xff1a;独立按键&#xff01; 先说独立按键的内部结构&#xff1a; 它相当于一种电子开关&#xff0c;按下时开关接通&#xff0c;松开时开关断开&#xff0c;实现原理是通过轻触按键内部的金属弹片受力弹动来实…

剧本杀小程序开发:打造沉浸式推理体验

随着社交娱乐形式的多样化&#xff0c;剧本杀逐渐成为年轻人喜爱的聚会活动。而随着技术的发展&#xff0c;剧本杀小程序的开发也成为了可能。本文将探讨剧本杀小程序开发的必要性、功能特点、开发流程以及市场前景。 一、剧本杀小程序开发的必要性 剧本杀是一种角色扮演的推…

鸿蒙端云一体化简单项目

文章目录 前言端云一体化服务端客户端云数据库总结 一、前言 鸿蒙系统在不断地成熟&#xff0c;现在有了鸿蒙端云一体化开发模式。什么是端云一体化呢&#xff0c;简单点就是你原本是客户端开发的&#xff0c;项目中只是客户端的代码&#xff0c;端云一体化呢&#xff0c;就…

【MyBatis】#{} 和 ${}

目录 1. #{} 使用示例&#xff1a; 2. ${} 使用示例&#xff1a; SQL注入 使用#{}的情况&#xff1a; 使用${}的情况&#xff1a; MyBatis是一种用于Java语言的持久层框架&#xff0c;它简化了数据库操作的过程。在MyBatis中&#xff0c;我们经常会看到两种不同的参数占…

华为云WAF,开启web网站的专属反爬虫防护罩

背景 从保护原创说起 作为一个原创技术文章分享博主&#xff0c;日常除了Codeing就是总结Codeing中的技术经验。 之前并没有对文章原创性的保护意识&#xff0c;直到在某个非入驻的平台看到了我的文章&#xff0c;才意识到&#xff0c;辛苦码字、为灵感反复试验创作出来的文…

苹果macOS 恶意软件家族被曝光:通过破解软件分发,可窃取敏感信息

卡巴斯基安全实验室近日发布博文&#xff0c;发现了一种针对苹果 macOS 设备的新型恶意软件家族&#xff0c;并提醒苹果 Mac 用户谨慎下载破解软件。 报告称这种新型恶意软件家族高度复杂&#xff0c;主要伪装成为各种知名 macOS 软件的破解版分发&#xff0c;用户下载恶意 PKG…

ISO 14229和UDS:汽车诊断的黄金标准

UDS简介&#xff1a; UDS是Unified Diagnostic Services的缩写&#xff0c;全名统一诊断服务。它是一种用于汽车电子控制单元&#xff08;ECU&#xff09;之间进行诊断和通信的标准协议&#xff0c;属于ISO 14229标准的一部分。 UDS的起源和背景&#xff1a; UDS的起源可以追…

HarmonyOS 鸿蒙应用开发 (七、HTTP网络组件 axios 介绍及封装使用)

在HarmonyOS应用开发中&#xff0c;通过HTTP访问网络&#xff0c;可以使用官方提供的ohos.net.http模块。但是官方提供的直接使用不太好使用&#xff0c;需要封装下才好。推荐使用前端开发中流行的axios网络客户端库&#xff0c;如果是前端开发者&#xff0c;用 axios也会更加顺…

Java笔记(死锁、线程通信、单例模式)

一、死锁 1.概述 死锁 : 死锁是指两个或两个以上的进程在执行过程中&#xff0c;由于竞争资源或者由于彼此通信而造成的一种阻塞的现象&#xff0c;若无外力作用&#xff0c;它们都将无法往下执行。此时称系统处于死锁状态或系统产生了死锁&#xff0c;这些永远在互相等待的进…

vusui css 使用,简单明了 适合后端人员 已解决

vusui-cssopen in new window 免除开发者繁复的手写 CSS 样式&#xff0c;让 WEB 前端开发更简单、灵活、便捷&#xff01;如果喜欢就点个 ★Staropen in new window 吧。 移动设备优先&#xff1a; vusui-css 包含了贯穿于整个库的移动设备优先的样式。浏览器支持&#xff1a…

【每日一题】最大合金数

文章目录 Tag题目来源解题思路方法一&#xff1a;二分枚举答案 写在最后 Tag 【二分枚举答案】【数组】【2024-01-27】 题目来源 2861. 最大合金数 解题思路 方法一&#xff1a;二分枚举答案 思路 如果我们可以制造 x 块合金&#xff0c;那么一定也可以制造 x-1 块合金。于…

《合成孔径雷达成像算法与实现》Figure5.18

clc clear close all距离向参数 R_eta_c 20e3; % 景中心斜距 Tr 25e-6; % 发射脉冲时宽 Kr 0.25e12; % 距离向调频率 Fr 7.5e6; % 距离向采样率 Nrg 256; % 距离线采样点数 Bw abs(Kr*Tr); …

【C++干货铺】C++中的IO流和文件操作

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 C语言的输入输出 流是什么&#xff1f; C的IO流 C标准IO流 C文件IO流 文本文件读写 二进制文件的读写 stringstream的简单介绍 将数值类型数据格式化为字…

JS中的try...catch

一、定义和结构 作用&#xff1a;捕获同步执行代码下的异常错误 在没有使用try...catch的情况下&#xff0c;同步代码执行遇到异常会报错&#xff0c;并中断后续代码执行&#xff1b; 在使用try...catch的情况下&#xff0c;同步代码执行遇到异常会抛出异常&#xff0c;并继续…

线性代数----------学习记录

线性代数发展历程 &#xff08;1&#xff09;线性方程组&#xff1a;例如二元一次方程组&#xff1b; &#xff08;2&#xff09;行列式&#xff1a;determinant,克莱默&#xff0c;莱布尼兹&#xff1b; &#xff08;3&#xff09;矩阵&#xff1a;方程个数与未知数的个数可…

【前端工程化】环境搭建 nodejs npm

文章目录 前端工程化是什么&#xff1f;前端工程化实现技术栈前端工程化环境搭建 &#xff1a;什么是Nodejs如何安装nodejsnpm 配置和使用npm 介绍npm 安装和配置npm 常用命令 总结 前端工程化是什么&#xff1f; 前端工程化是使用软件工程的方法来单独解决前端的开发流程中模块…

JAVAEE初阶 网络编程(五)

TCP协议 一.TCP协议图二. TCP中的关键协议确认应答后发先至机制引入序号和确认序号 超时重传去重机制 建立连接三次握手 一.TCP协议图 我们可以发现&#xff0c;相比于UDP&#xff0c;TCP协议明显复杂很多&#xff0c;比如32位序号和32位确认序号&#xff0c;4位首都长度&#…