【Spring】多环境切换
🎈博客主页:🌈我的主页🌈
🎈欢迎点赞 👍 收藏 🌟留言 📝 欢迎讨论!👏
🎈本文由 【泠青沼~】 原创,首发于 CSDN🚩🚩🚩
🎈由于博主是在学小白一枚,难免会有错误,有任何问题欢迎评论区留言指出,感激不尽!🌠个人主页
目录
- 🌟 一、Java配置
- 🌟 二、XML配置
- 🌟 三、原理分析
- 🌟 三、自定义Profile
🌟 一、Java配置
首先创建一个 DataSource 类:
public class DataSource {private String username;private String password;private String url;@Overridepublic String toString() {return "DataSource{" +"username='" + username + '\'' +", password='" + password + '\'' +", url='" + url + '\'' +'}';}
}
向 Spring 容器中注册多个 DataSource,并且在注册的时候设置 Profile,只有当条件满足的时候,才向 Spring 容器中注册相应的 Bean,否则不注册
public class JavaConfig {@Bean@Profile("dev")DataSource devDataSource(){DataSource dev = new DataSource();dev.setUsername("dev");dev.setPassword("dev");dev.setUrl("jdbc:mysql:3306/dev");return dev;}@Bean@Profile("prod")DataSource prodDataSource(){DataSource prod = new DataSource();prod.setUsername("prod");prod.setPassword("prod");prod.setUrl("jdbc:mysql:3306/prod");return prod;}}
这里到底向 Spring 容器中注册多少个 DataSource,主要还是看条件是否满足,如果有多个条件满足,那么就注册多个 DataSource 实例到 Spring 容器中,否则就不注册。
最后,启动容器:
public static void main(String[] args) {//这里注意,不能添加配置类,如果添加了配置类,则 refresh 方法会被调用,而 Spring 容器的初始化则正是从这里开始的//此时,我们还没设置当前系统环境AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();//这里注意,不能添加配置类,如果添加了配置类,则 refresh 方法会被调用,而 Spring 容器的初始化则正是从这里开始的//此时,我们还没设置当前系统环境ConfigurableEnvironment evn = ctx.getEnvironment();evn.setActiveProfiles("prod");//此时再去设置配置类ctx.register(JavaConfig.class);//开始初始化容器ctx.refresh();DataSource dataSource = ctx.getBean(DataSource.class);System.out.println(dataSource);}
启动容器的时候,一开始不要传配置类进去,如果传了,则 refresh 方法会被自动调用,而此时我们还没设置容器的环境!所以,使用无参构造方法创建 AnnotationConfigApplicationContext 对象,然后设置系统环境,再去设置配置类,最后再去初始化容器
🌟 二、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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><beans profile="dev"><bean class="com.dong.demo3.DataSource" ><property name="username" value="dev"/><property name="password" value="dev"/><property name="url" value="jdbc:mysql:3306/dev"/></bean></beans><beans profile="prod"><bean class="com.dong.demo3.DataSource" ><property name="username" value="prod"/><property name="password" value="prod"/><property name="url" value="jdbc:mysql:3306/prod"/></bean></beans>
</beans>
这个是在 父标签 beans 中设置条件,满足对应的条件,父标签中的所有 Bean 才会被初始化
public class XMLDemo1 {public static void main(String[] args) {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();ctx.getEnvironment().addActiveProfile("prod");ctx.setConfigLocation("beans1.xml");ctx.refresh();DataSource bean = ctx.getBean(DataSource.class);System.out.println(bean);}
}
🌟 三、原理分析
@Profile注解的定义就是一个组合注解:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 从这里可以看到,本质上就是一个条件注解,条件则是 ProfileCondition
@Conditional(ProfileCondition.class)
public @interface Profile {/*** The set of profiles for which the annotated component should be registered.*/String[] value();}
那我们来看下 ProfileCondition:
class ProfileCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 这句话实际上就是查询到 Profile 注解的所有属性// 对于 Profile 注解来说,实际上就只有 value 属性// value->dev value->prodMultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());if (attrs != null) {// attrs.get("value") 表示读取属性中的 value 属性,value 属性的值是一个数组,所以这里需要遍历for (Object value : attrs.get("value")) {//判断当前系统环境中是否包含这个 valueif (context.getEnvironment().matchesProfiles((String[]) value)) {return true;}}return false;}return true;}}
🌟 三、自定义Profile
首先,先自定义注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Conditional(MyCondition.class)
public @interface MyProfile {String[] value();
}
然后自定义条件,在自定义条件中解析注解:
public class MyCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(MyProfile.class.getName());if(attrs != null){List<Object> list = attrs.get("value");for (Object value : list) {boolean b = context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value));if(b){return true;}}}return false;}
}
最后使用自定义注解:
public class JavaConfig {@Bean@MyProfile("dev")DataSource devDataSource(){DataSource dev = new DataSource();dev.setUsername("dev");dev.setPassword("dev");dev.setUrl("jdbc:mysql:3306/dev");return dev;}@Bean@MyProfile("prod")DataSource prodDataSource(){DataSource prod = new DataSource();prod.setUsername("prod");prod.setPassword("prod");prod.setUrl("jdbc:mysql:3306/prod");return prod;}}
启动容器:
public static void main(String[] args) {//这里注意,不能添加配置类,如果添加了配置类,则 refresh 方法会被调用,而 Spring 容器的初始化则正是从这里开始的//此时,我们还没设置当前系统环境AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();//这里注意,不能添加配置类,如果添加了配置类,则 refresh 方法会被调用,而 Spring 容器的初始化则正是从这里开始的//此时,我们还没设置当前系统环境ConfigurableEnvironment evn = ctx.getEnvironment();evn.setActiveProfiles("prod");//此时再去设置配置类ctx.register(JavaConfig.class);//开始初始化容器ctx.refresh();DataSource dataSource = ctx.getBean(DataSource.class);System.out.println(dataSource);}
相关文章:
【Spring】多环境切换
🎈博客主页:🌈我的主页🌈 🎈欢迎点赞 👍 收藏 🌟留言 📝 欢迎讨论!👏 🎈本文由 【泠青沼~】 原创,首发于 CSDN🚩…...
python经典百题之求10000之内的素数
题目:求10000之内的素数 程序分析 求10000之内的素数是一个常见的问题。素数是大于1且只能被1和自身整除的整数。我们可以使用循环遍历10000以内的每个数,判断其是否是素数。 方法1: 简单遍历法 遍历2到10000之间的每个数,判断其是否为素…...
ROS2 从头开始:第 5 部分 - 并发、执行器和回调组
一、说明 让我们回到基础。并发意味着系统或软件可以同时运行许多任务。例如,在单核 CPU 机器上,可以通过使用线程来实现并发。本文探讨了...
笔试强训Day3
学了一坤时Linux,赶紧来俩道题目放松放松。 T1:在字符串中找出连续最长的数字串 链接:在字符串中找出连续最长的数字串__牛客网 输入一个字符串,返回其最长的数字子串,以及其长度。若有多个最长的数字子串,…...
软考软件设计师-存储管理-文件管理-计算机网络(中
文章目录 一、存储管理页面置换算法 (最佳OPT)存储页面-先进先出置换算法(FIFO)最久未使用算法(最近最久未使用LRU) 二、文件管理初识文件管理文件目录-绝对路径文件管理-文件的结构文件管理-索引的分配 空闲存储空间的管理(位示图法)三、计算…...
Vue3的学习
create-vue创建vue3项目 create-vue是官方新的脚手架工具,底层切换到了vite(下一代构建工具),为开发提供急速响应 前提环境条件:控制面板输入node -v,显示的是安装了16.0或更高版本的Node.js创建一个Vue应…...
什么是Peppol ID?如何创建?
Peppol 网络的两大优势是安全和高效,由于Peppol 最常用于电子发票,因此这些优势在电子发票上展露无遗。相比之下,通过电子邮件发送 PDF 格式的发票和其他文件不仅处理成本较高,而且容易出现发票欺诈。 如果您所在的公共部门组织或…...
Spring注解大揭秘:@Component、@Service、@Repository详解
Spring注解大揭秘:Component、Service、Repository详解 前言比较 前言 想象一下,你正在构建一个复杂的Spring应用程序。你需要管理各种不同类型的组件,包括服务层、数据访问层和通用组件。Spring的Component、Service和Repository注解就像是你…...
Innodb底层原理与Mysql日志机制
MySQL内部组件结构 Server层 主要包括连接器、词法分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,…...
浅谈大数据背景下用户侧用电数据在电力系统的应用与发展分析
安科瑞 华楠 摘要:随着能源互联网、互联网、新型传感技术的持续推进,电力用户侧用电数据呈现指数级剧增、异构性增强的情况,逐渐构成了用户侧用电行为大数据。然而目前对电力领域的数据价值挖掘于电网内部和电源端,用户侧庞大且蕴…...
20230919在WIN10下使用python3将PDF文档转为DOCX格式的WORD文档
20230919在WIN10下使用python3将PDF文档转为DOCX格式的WORD文档 2023/9/19 11:20 python pdf word https://blog.csdn.net/u013185349/article/details/130059657 Python实现PDF转Word文档 AcceptedLin 已于 2023-04-10 14:45:17 修改 1243 收藏 1 文章标签: pd…...
PCR检测试剂——博迈伦
PCR(聚合酶链式反应)是一种常用的分子生物学技术,被广泛应用于基因分型、基因表达分析、病原体检测等领域。在PCR实验中,PCR检测试剂是必不可少的重要组成部分,它们包括引物、酶、缓冲液和核苷酸。 1. 引物(…...
spring一个项目多个模块聚合打包问题解决方案
文章目录 1.问题描述:2.解决方案一、创建聚合父工程二、创建子模块(module)三、编写子模块代码1.模块1(demo-one)2.模块2(demo-tow) 四、创建聚合模块 (demo-starter)1. …...
Linux设备树(Device Tree)何时被解析
Linux设备树(Device Tree)是在内核启动阶段就会被解析。当 Linux 内核启动的时候,它会读取设备树文件(dtb文件)并根据里面的信息来组织设备、加载驱动等。在驱动代码里,通常我们是在驱动初始化(…...
【Elasticsearch】数据简单操作(二)
简介:Elasticsearch(ES)是一个开源的分布式搜索和分析引擎,用于快速存储、搜索和分析大量数据。它具有高性能、可扩展性和灵活性的特点,被广泛用于构建实时搜索、日志分析、数据可视化等应用。 本文主要介绍ES索引的操…...
4 vCPU 实例达成 100 万 JSON API 请求/秒的优化实践
“性能工程” (Performance engineering)是个日渐流行的概念。顾名思义“性能工程”是包含在系统开发生命周期中所应用的一个技术分支,其目的就是确保满足非功能性的性能需求,例如:性能、可靠性等。由于现代软件系统变…...
呼叫中心系统有什么优势
在随着企业的管理水平也在不断提高。企业经营管理中所涉及到的各种复杂问题都有逐渐凸显出来。传统的呼叫中心已无法满足企业服务需求和客户满意度变化的要求。因此通过呼叫中心系统将企业业务流程和数据整合起来进行管理和运营已经成为目前企业管理领域中较为流行和成熟之选。…...
如何在linux操作系统下安装nvm
本文主要介绍如何在linux操作系统下安装nvm,如果想知道nvm如何在windows操作系统下使用,请参考文章如何通过nvm管理多个nodejs版本_nvm 查看所有node版本-CSDN博客。 1、nvm下载 nvm全称Node Version Manager,即Node版本管理器。访问官网地址…...
Linux 入门:基本指令
本篇文章来介绍我们在初学Linux时可以会碰倒的一些基本指令,让我们对这些指令有一个基本的了解。 目录 01. ls 指令 02. pwd 命令 03. cd 指令 04. touch 指令 05. mkdir 指令(重要) 06. rmdir指令 && rm 指令(重…...
IP转地理位置:探讨技术与应用
IP地址是互联网上设备的唯一标识符,而将IP地址转换为地理位置信息是网络管理、安全监控和市场定位等领域中的一项重要任务。本文将深入探讨IP转地理位置的技术原理和各种应用场景。 IP地址与地理位置 IP地址(Internet Protocol Address)是一…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
