Spring Boot 系统学习第五天:Spring循环依赖实战经验

1 概述

        本篇主要介绍使用依赖注入的一些实战经验。

2 把握Bean的作用域

        前面说到Setter方法注入时,提到了Spring中的Bean作用域的概念。作用域描述了Bean在Spring IoC容器上下文中的生命周期和可见性。现在讨论Spring框架中不同类型的Bean作用域及其在使用上的指导规则。

        如果想要通过注解来设置Bean的作用域,可以使用下面示例代码:

@Configuration
public class Appcofig {@Bean@Scope("singleton")public HealthRecordService createHealthRecordService(){return new HealthRecordServiceImpl();}
}
public interface HealthRecordService {
}
public class HealthRecordServiceImpl implements HealthRecordService{
}

        可以看到这里使用了一个@Scope注解来指定Bean的作用域为单例的singleton。在Spring中,除了单例作用域之外,还有一个prototype,即原型作用域,也可成为多例作用域,与单例作用域进行区分。使用方式上,同样可以使用下列代码进行设置。

@Configuration
public class Appcofig1 {@Bean@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)public HealthRecordService createHealthRecordService(){return new HealthRecordServiceImpl();}
}

        在SpringIoC容器中,Bean的默认作用域是单例,也就是不管有多少个对Bean的引用,容器只会创建一个实例。而原型作用域则不同,每次请求Bean时,Spring IoC容器都会创建一个新的对象实例。

        从两种作用域的效果而言,总结出一条开发上的经验,即对于有状态的Bean,应该使用原型作用域,反之则使用单例作用域。

        那么,什么样的Bean是有状态的呢?结合Web应用程序,可以明确对于每次HTTP请求而言,都应该创建一个Bean来代表这一次的请求对象。同样,对于会话而言,也需要针对每个会话创建一个会话状态对象。这些都是创建的有状态的Bean。为了更好地管理这些Bean的生命周期,Spring还专门针对Web开发场景提供了对应的request和session作用域。

3 灵活使用注解配置

        在使用Spring依赖注入类型时,通常可以使用XML配置、Java代码配置以及注解配置这三种方式。随着Spring Boot框架的流程,使用注解配置已经成为目前最主流的开发方法。除了前面已经给出的最常见的@Autowired注解,Spring Boot框架还提供了一组非常有用的注解帮助我们更好的管理所注入的对象,包括@Primary注解和@Qualifier注解。

        在Spring IoC容器中,针对HealthRecordService这样一种接口类型,原则上容器只允许注入一个实现类。如果存在该类型的多个对象实例,那么容器就会NoUniqueBeanDefinitionException,意味着容器无法决定选择哪一个实例来进行注入。这时候就可以使用@Primary注解来帮助容器做出选择,该注解的使用方式如下:

@Component
public class HealthRecordServiceImplA implements HealthRecordService{
}
@Component
@Primary
public class HealthRecordServiceImplB implements HealthRecordService{
}

        这时候,Spring IoC容器只会注入HealthRecordServiceImplB这个实例类,这在管理针对某种类型的多个实例时非常有效。

        和@Primary注解的应用场景类似,@Qualifier注解为我们选择实例类进行注入提供了更加灵活的实现方式,代码如下:

@Component
@Qualifier("healthRecordServiceImplA")
public class HealthRecordServiceImplA implements HealthRecordService{
}
@Component
@Qualifier("healthRecordServiceImplB")
public class HealthRecordServiceImplB implements HealthRecordService{
}

        可以看到,这里对不同的实现类,通过@Qualifier注解设置了不同的名称,这样在使用时就可以通过该名称获取不同的实例,代码如下:

public class HealthRecordServiceImplA implements HealthRecordService{@Autowired@Qualifier("healthRecotdServiceA")private HealthRecordService healthRecordService;
}

4 设置组件扫描范围

        在Spring中,可以通过设置组件扫描范围来简化Bean的注入配置。因为任何类都位于某一个包接口之下,所以Spring提供了一个@ComponentScan注解,该注解在需要大规模对象注入的场景下非常有用,代码如下:

@Configuration
@ComponentScan(basePackages = "com.jay")
public class Appcofig2 {
}

        在这个示例中,Spring会扫描由basePackages指定的包路径com.jay及其子路径下的所有Bean,并把它们注入到容器中,当前,首先需要再这些类上添加@Component注解以及由该注解衍生的@Service、@Pepository、@Controler等注解。

5 不同配置的性能分析

        首先要讨论的是前面介绍的@ComponentScan注解。因为该注解会扫描basePackages指定的包中的所有组件,所以如果指定包中的组件并不需要在应用程序启动时就全部加载到容器中。那么对包路径进行精细化设计是一个实践技巧。例如,可以通过设置一个列表来细化具体的包结构路径。代码如下:

@Configuration
@ComponentScan(basePackages = "com.jay.controller","com.jay.service")
public class Appcofig2 {
}

        然后要讨论的是单例模式和原型模式对性能的影响。在Spring中,当把Bean范围设置为prototype,每次请求Bean时,Spring IoC容器都会创建一个新的对象实例。所以,使用原型模式在创建过程中会对性能产生影响,对那些初始化过程需要消耗巨大资源的对象而言尤其如此,这些对象常见的有网络连接对象、数据库连接对象等。因此,对这些对象,应该避免使用原型模式。或者,应该在使用前仔细设计并对性能进行充分测试。

        最后一个值得讨论的性能分析点在于Spring IoC容器的延迟加载(Lazy Loading)和预加载(Preloading)机制。通过@Autowired注入的Bean都是在Spring IoC容器启动时被创建和初始化的,这个过程被称为预加载。但有时候,希望能够延迟Bean的加载时机,这时候就可以使用@Lay注解,示例如下:

@Component
@Lazy
public class HealthRecordServiceImpl implements HealthRecordService{
}

        添加了@Lazy注解的效果是只有在使用到这个Bean时它才会去初始化,而不是在Spring IoC容器启动时直接初始化,这样就可以节省容器资源。

        延迟加载确保在请求时动态加载Bean,预加载确保在使用Bean之前加载Bean。Spring IoC容器默认使用预加载。然后,在容器启动时就加载所有类并不是一个明智的决定,因为有些Bean实例会非常消耗资源。应该根据实际情况选择具体的加载方法。

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

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

相关文章

Java 枚举类型深入解析

在Java中,枚举(enum)是一种特殊的数据类型,它允许一个变量是预定义的常量集合中的一个值。枚举类型在许多场景中都非常有用,比如定义一组明确的常量、简化代码的可读性和维护性等。本文将详细讲解Java中的枚举类型&…

对比WPF和Avalonia的边框渲染差异

众所周知&#xff0c;诸如Border、Rectangle等元素&#xff0c;是具有边框的。但在WPF和Avalonia中&#xff0c;边框的渲染机制有所不同。 如下代码&#xff0c;Border的边框和背景色均为黑色&#xff0c;并且将透明度设为0.5&#xff1a; <Border Width"100" H…

模拟实现C++vector

一&#xff1a;C库中对于vector的介绍 vector的底层其实就是数据结构中的顺序表&#xff0c;顺序表的底层就是变长数组&#xff0c;是一段连续的物理空间 在下面的实现中&#xff0c;重点实现的是其中的迭代器和插入删除&#xff0c;下标访问等功能&#xff0c;模拟实现模板类…

BottomSheetDialog高度自适应,布局RecyclerView使用问题

public class CultureBottomDialogView {/*** 标题*/private static TextView textTitle;/*** 关闭按钮*/private static TextView textClose;/*** 列表*/private static RecyclerView recyclerView;private static BottomDialogAdapter dialogAdapter;private static List<…

15-JavaScript 中的 `call`、`apply` 和 `bind`

JavaScript 中的 call、apply 和 bind 笔记分享 在 JavaScript 中&#xff0c;函数作为一等公民&#xff0c;可以像其他对象一样被操作。这种特性使得我们可以通过特定的方法来控制函数的调用环境&#xff08;即 this 的值&#xff09;。call、apply 和 bind 是三个常用的方法…

消息队列RabbitMQ

1. 消息队列概述 1.1 什么是消息队列 消息队列是一种用于在分布式系统中传递消息的数据结构。它采用先进先出&#xff08;FIFO&#xff0c;First In First Out&#xff09;的方式进行数据存储和管理。消息队列能够解耦生产者和消费者&#xff0c;从而实现系统的松散耦合&#…

Flutter 视频播放利器:Chewie 的介绍与使用

在移动应用开发中&#xff0c;视频播放功能是常见的需求之一。Flutter 作为跨平台开发框架&#xff0c;其生态系统中有许多用于视频播放的插件。其中&#xff0c;Chewie 是一个非常受欢迎且功能强大的视频播放器插件&#xff0c;它是对官方 video_player 插件的包装&#xff0c…

Vue中使用vuex进行全局数据共享处理

1、简介 在之前的博文中&#xff0c;介绍了如何进行组件之间的数据传递&#xff0c;但是对于所有组件共享的变量来说&#xff0c;使用组件之间的数据传递实现复杂&#xff0c;因此本文引入vuex进行全局数据共享。 2、vuex的下载配置 2.1、vuex的下载 # 对于vue2来说&#xf…

第十六章 创建Web客户端 - 修改生成的客户端类

文章目录 第十六章 创建Web客户端 - 修改生成的客户端类修改生成的客户端类调整生成的类以处理极长的字符串 第十六章 创建Web客户端 - 修改生成的客户端类 修改生成的客户端类 生成 Web 客户端类后&#xff0c;通常不需要编辑该类。相反&#xff0c;可以编写代码来创建 Web …

IP地址开启HTTPS方法

可以使用IP地址申请SSL证书&#xff0c;申请之前必须是公网IP地址&#xff0c;不支持内网IP地址申请。 申请过程需要确定IP地址外网可以访问&#xff0c;这里特别注意只是申请过程中可以访问。访问验证过程必须采取80端口、443端口两者选择1个&#xff0c;不可以用其它端口进行…

下载视频怎么转换MP4?wmv转换mp4,推荐这3种方法

在数字化时代&#xff0c;我们经常需要从网上下载各种视频&#xff0c;但有时候下载的视频并不是我们想要的格式&#xff0c;比如WMV。为了能在更多的设备上播放或进行编辑&#xff0c;我们可能需要将其转换为更通用的MP4格式。 那么&#xff0c;下载的视频如何转换成MP4呢&am…

第三篇 编译器和译码器

实验三 编码器和译码器 3.1 实验目的 上一章节我们学习了简单组合逻辑电路——多路数据选择器&#xff0c;在本章节我们将学习另外一种数字系统中常见的简单组合逻辑电路——编码器和译码器。然后通过一个设计一个简易的计算器让大家进一步巩固FPGA开发的流程和方法。 本节您…

“神经网络之父”和“深度学习鼻祖”Geoffrey Hinton

“神经网络之父”和“深度学习鼻祖”Geoffrey Hinton在神经网络领域数十年如一日的研究&#xff0c;对深度学习的推动和贡献显著。 一、早期贡献与突破 反向传播算法的引入&#xff1a;Hinton是将反向传播&#xff08;Backpropagation&#xff09;算法引入多层神经网络训练的…

【C++进阶】深入STL之vector:构建高效C++程序的基石

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;C “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;模拟实现string &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀STL之vector &#x1f4d2;1.ve…

网络编程(七)

网络编程&#xff08;七&#xff09; UNIX域套接字&#xff08;本地间进程间通信的技术&#xff09;&#xff08;S文件&#xff09;基于TCP传输基于UDP传输 UNIX域套接字&#xff08;本地间进程间通信的技术&#xff09;&#xff08;S文件&#xff09; socket同样也可以用于本…

OpenCV-绘制虚线

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 功能函数 // 绘制虚线 void DrawDottedLine(cv::Mat &input, cv::Point p1, cv::Point p2, cv::Scalar color, int thickne…

Android Graphics 显示系统 - Android Jank detection with FrameTimeline

“ 最近有公司同事在处理UI卡顿及FPS自动化监测的问题&#xff0c;我也顺便看了一点相关的内容&#xff0c;其中在Perfetto的官方说明文档中有一篇关于利用FrameTimeLine进行Jank监测的解读&#xff0c;个人觉得蛮有意思的&#xff0c;借助工具翻译该篇文章并加上本人拙劣的解读…

C++系列-类模板

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 类模板的定义格式&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; template<class T> class Stack { public:Stack(size_…

【Java EE】网络原理——HTTPS

目录 1.HTTPS是什么 2.“加密”是什么 3.HTTPS的工作过程 3.1引入对称加密 3.2 引入非对称加密 4.中间人攻击 5.引入证书 6. 理解数据签名 7.通过证书解决中间人攻击 7.1 查看浏览器的授信任证书发布机构 7.2 中间人有没有可能篡改证书&#xff1f; 7.3 中间人整个掉…

解释Java中的反射API

一、技术难点 Java中的反射API允许程序在运行时获取类的内部信息&#xff0c;并可以操作这些类的字段、方法和构造器。虽然反射为Java程序员提供了极大的灵活性&#xff0c;但同时也带来了一些技术上的难点和挑战&#xff1a; 性能问题&#xff1a;反射操作相比直接操作对象通…