Spring系列15:Environment抽象

Python微信订餐小程序课程视频

https://edu.csdn.net/course/detail/36074

Python实战量化交易理财系统

https://edu.csdn.net/course/detail/35475

本文内容

  1. Environment抽象的2个重要概念
  2. @Profile 的使用
  3. @PropertySource 的使用

Environment抽象的2个重要概念

Environment 接口表示当前应用程序运行环境的接口。对应用程序环境的两个关键方面进行建模:配置文件( profiles )和属性(properties)。与属性访问相关的方法通过 PropertyResolver 超接口公开。环境对象的配置必须通过 ConfigurableEnvironment 接口完成,该接口从所有 AbstractApplicationContext 子类 getEnvironment() 方法返回

环境与配置文件

配置文件是一个命名的、逻辑的 bean 定义组,仅当给定的配置文件处于活动状态时才向容器注册。可以将 Bean 分配给配置文件,无论是在 XML 中定义还是通过注释 @Profile 定义;与配置文件相关的环境对象的作用是确定哪些配置文件(如果有)当前处于活动状态,以及哪些配置文件(如果有)默认应该是活动的

环境与属性

属性在几乎所有应用程序中都发挥着重要作用,并且可能源自多种来源:属性文件、JVM 系统属性、系统环境变量、JNDI、servlet 上下文参数、属性对象、map等。与属性相关的环境对象的作用是为用户提供一个方便的服务接口,用于配置属性源并从中解析属性

在 ApplicationContext 中管理的 Bean 可以注册为 EnvironmentAware 或 @Inject Environment,以便直接查询配置文件状态或解析属性。然而,在大多数情况下,应用程序级别的 bean 不需要直接与 Environment 交互,而是可能必须将 ${…} 属性值替换为属性占位符配置器,例如 PropertySourcesPlaceholderConfigurer,它本身是 EnvironmentAware 并且从 Spring 3.1 开始使用 context:property-placeholder 时默认注册 ,或是通过java bean的方式注册到容器中。

PropertySourcesPlaceholderConfigurer 分析可以阅读上一篇: Spring系列14:IoC容器的扩展点

接口源码粗览

接口继承关系

image-20220121175854817

接口源码如下提供配置文件相关的接口方法,其继承的 PropertyResolver 提供属性相关的接口。

public interface Environment extends PropertyResolver {// 当前激活的配置文件列表// 设置系统属性值 spring.profiles.active=xxx 可激活// 或是调用 ConfigurableEnvironment#setActiveProfiles(String...)激活String[] getActiveProfiles();// 当没有明确设置活动配置文件时,默认配置文件集返回为活动状态。String[] getDefaultProfiles();// 返回活动配置文件是否与给定的 Profiles 匹配boolean acceptsProfiles(Profiles profiles);}

PropertyResolver 是针对任何底层源解析属性的接口,主要接口方法如下。有一个非常重要的实现类是 PropertySourcesPlaceholderConfigurer 。

public interface PropertyResolver {// 是否包含属性boolean containsProperty(String key);// 获取属性值String getProperty(String key);// 获取属性值带默认值String getProperty(String key, String defaultValue);// 获取属性值T getProperty(String key, Class targetType);// 获取属性值带默认值T getProperty(String key, Class targetType, T defaultValue);// 获取属性值String getRequiredProperty(String key) throws IllegalStateException;// 获取属性值T getRequiredProperty(String key, Class targetType) throws IllegalStateException;// 解析给定文本中的 ${...} 占位符String resolvePlaceholders(String text);// 解析给定文本中的 ${...} 占位符String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;}

ConfigurablePropertyResolver 是大多数 PropertyResolver 类型都将实现的配置接口。提供用于访问和自定义将属性值从一种类型转换为另一种类型时使用的 ConversionService 的工具。

public interface ConfigurablePropertyResolver extends PropertyResolver {ConfigurableConversionService getConversionService();void setConversionService(ConfigurableConversionService conversionService);// 设置占位符前缀 默认的 "${"怎么来的void setPlaceholderPrefix(String placeholderPrefix);// 设置占位符后缀 默认的 "}"怎么来的void setPlaceholderSuffix(String placeholderSuffix);// 设置占位符值分分隔符 默认的 ":"怎么来的void setValueSeparator(@Nullable String valueSeparator);void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders);void setRequiredProperties(String... requiredProperties);void validateRequiredProperties() throws MissingRequiredPropertiesException;}

ConfigurableEnvironment是大多数环境类型都将实现的配置接口。提供用于设置活动和默认配置文件以及操作基础属性源的工具。允许客户端通过 ConfigurablePropertyResolver 超级接口设置和验证所需属性、自定义转换服务等。

public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {void setActiveProfiles(String... profiles);void addActiveProfile(String profile);void setDefaultProfiles(String... profiles);MutablePropertySources getPropertySources();// 关键的系统属性 System#getProperties()Map getSystemProperties();// 关键的系统环境 System#getenv()Map getSystemEnvironment();void merge(ConfigurableEnvironment parent);}

@Profile 的使用

@Profile 表示当一个或多个profiles处于活动状态时,组件有资格注册。可以通过以下的方式设置活跃的一个或是多个配置文件:

  • 编程方式:ConfigurableEnvironment#setActiveProfiles(String…)
  • 启动参数: -Dspring.profiles.active=“profile1,profile2”
  • xml配置方式:

使用案例

来看一个实际场景:不同环境要求在容器中注入不同类型的的数据源,dev环境使用H2,生产环境prod使用Mysql,default环境使用 HSQL。

定义不同环境的数据源,并标识 @Profile

@Configuration
@ComponentScan
public class AppConfig {// 测试环境数据源H2@Profile("dev")@Beanpublic DataSource devDataSource() {DataSource dataSource = new DataSource();dataSource.setType("H2");dataSource.setUrl("jdbc:h2:xxxxxx");return dataSource;}// 生产环境数据源mysql@Profile("prod")@Beanpublic DataSource prodDataSource() {DataSource dataSource = new DataSource();dataSource.setType("mysql");dataSource.setUrl("jdbc:mysql:xxxxxx");return dataSource;}// default 环境的 HSQL@Profile("default")@Beanpublic DataSource defaultDataSource() {DataSource dataSource = new DataSource();dataSource.setType("HSQL");dataSource.setUrl("jdbc:HSQL:xxxxxx");return dataSource;}}

测试程序,首先不指定 profile

@org.junit.Test
public void test\_profile() {AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext();
// context.getEnvironment().setActiveProfiles("prod");context.register(AppConfig.class);context.refresh();DataSource dataSource = context.getBean(DataSource.class);System.out.println(dataSource.getType());context.close();
}
// 输出结果
HSQL

从结果可知,注册到容器中的 default 环境对应的 HSQL

指定 profile 为 prod ,观察输出

context.getEnvironment().setActiveProfiles("prod")
// 结果
mysql

从结果可知,注册到容器中的 prod 环境对应的 mysql 。

支持逻辑操作符

支持与或非操作组合

  • &
  • |

组合&和|必须使用小括号

反例:production & us-east | eu-central

正例:production & (us-east | eu-central)

使用 @Profile 自定义组合注解

定义组合注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("production")
public @interface Production {
}

使用

@Configuration
@Production
public class MyConfiguration {
}

如果@Configuration 类用@Profile 标记,则与该类关联的所有@Bean 方法和@Import 注释都将被绕过,除非一个或多个指定的配置文件处于活动状态。

使用xml指定 profile

标签中的 profile元素的可以指定配置文件。

xml version="1.0" encoding="UTF-8"?
<beans profile="prod"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"><bean class="com.crab.spring.ioc.demo13.DataSource" id="dataSource"><property name="type" value="mysql"/><property name="url" value="jdbc:mysql/xxxxx"/>bean>beans>

PropertySource 抽象

Spring 的 Environment 抽象在可配置的属性源层次结构上提供搜索操作。来看下案例如何从Spring 容器获取属性。

@org.junit.Test
public void test\_property\_source() {ApplicationContext ctx = new GenericApplicationContext();Environment env = ctx.getEnvironment();boolean containsMyProperty = env.containsProperty("my-property");System.out.println("Does my environment contain the 'my-property' property? " + containsMyProperty);
}

PropertySource 是对任何键值对源的简单抽象。Spring 的 StandardEnvironment 配置了两个 PropertySource 对象:

  • 一个表示一组 JVM 系统属性 (System.getProperties())
  • 一个表示一组系统环境变量 (System.getenv())
public class StandardEnvironment extends AbstractEnvironment {/** System environment property source name: {@value}. */public static final String SYSTEM\_ENVIRONMENT\_PROPERTY\_SOURCE\_NAME = "systemEnvironment";/** JVM system properties property source name: {@value}. */public static final String SYSTEM\_PROPERTIES\_PROPERTY\_SOURCE\_NAME = "systemProperties";// 自定义适合任何标准的属性源自定义一组属性源@Overrideprotected void customizePropertySources(MutablePropertySources propertySources) {propertySources.addLast(new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));}}

在属性源中查找属性是否存在的优先级顺序如下,从高到低:

  1. ServletConfig parameters (web上下文)
  2. ServletContext parameters (web.xml context-param entries)
  3. JNDI environment variables (java:comp/env/ entries)
  4. JVM system properties (-D command-line arguments)
  5. JVM system environment (operating system environment variables)

自定义 PropertySource

自定义 MyPropertySource 实现 Property 提供基于 Map 属性键值对的属性源

/*** 自定义 PropertySource* @author zfd* @version v1.0* @date 2022/1/22 22:13* @关于我 请关注公众号 螃蟹的Java笔记 获取更多技术系列*/
public class MyPropertySource extends PropertySource> {public MyPropertySource(String name, Map source) {super(name, source);}public MyPropertySource(String name) {super(name);}@Overridepublic Object getProperty(String name) {return this.source.get(name);}}

添加到Spring 容器环境中,优先级最高

@org.junit.Testpublic void test\_custom\_property\_source() {ConfigurableApplicationContext ctx = new GenericApplicationContext();MutablePropertySources sources = ctx.getEnvironment().getPropertySources();Map map = new HashMap<>();map.put("my-property", "xxx");sources.addFirst(new MyPropertySource("myPropertySource",map));// trueboolean containsMyProperty = ctx.getEnvironment().containsProperty("my-property");System.out.println("Does my environment contain the 'my-property' property? " + containsMyProperty);
}

@PropertySource 使用

相比上面的编程式添加 PropertySource,@PropertySource 注解为将 PropertySource 添加到 Spring 的环境中提供了一种方便且声明性的机制。直接看案例。

app.properties配置

testBean.name=xxx

配置类

@Configuration
// 注入配置文件
@PropertySource("classpath:demo13/app.properties")
public class AppConfig3 {@Autowiredprivate Environment env;@Beanpublic TestBean testBean() {TestBean testBean = new TestBean();testBean.setName(env.getProperty("testBean.name"));return testBean;}
}

测试结果观察

    @org.junit.Testpublic void test\_property\_source\_annotation() {AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(AppConfig3.class);TestBean testBean = context.getBean(TestBean.class);System.out.println(testBean.getName());}
// 结果
xxx

@PropertySource 中指定配置文件也是可以使用占位符${…}的。如果环境中属性值my.config.path已经存在则进行解析,否则使用默认值demo13

@Configuration
// 注入配置文件
@PropertySource("classpath:${my.config.path:demo13}/app.properties")
public class AppConfig3 {}

总结

本文介绍了Spring中的Environment抽象的2个重要概念:Bean定义配置文件和属性源。同时介绍了@Profile使用和@PropertySource 的使用。

本篇源码地址: https://github.com/kongxubihai/pdf-spring-series/tree/main/spring-series-ioc/src/main/java/com/crab/spring/ioc/demo13
知识分享,转载请注明出处。学无先后,达者为先!

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

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

相关文章

私有化轻量级持续集成部署方案--05-持续部署服务-Drone(上)

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 提示&#xff1a;本系列笔记全部存在于 Github&#xff0c; 可以直接在 Github 查看全部笔记 持续部署概述 持续部署是能…

PS图像菜单下计算命令

PS图像菜单下计算命令通过通道的混合模式得到的选区非常精细&#xff0c;从而调色的时候过度非常好。功能十分强大。 下面用计算命令中的"相加"和"减去"模式做实例解析&#xff0c;这里通道混合模式和图层混合模式原理是一样的。 原图&#xff1a; 实例目…

win10 VScode配置GCC(MinGW)

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 前提 安装 Visual Studio Code安装 C/C 扩展 for VS Code 也可以在vscode的extension界面搜索’c’查找插件安装 3. 获取最…

复制构造函数的用法及出现迷途指针问题

复制构造函数利用下面这行语句来复制一个对象&#xff1a; A (A &a) 从上面这句话可以看出&#xff0c;所有的复制构造函数均只有一个参数&#xff0c;及对同一个类的对象的引用 比如说我们有一个类A&#xff0c;定义如下&#xff1a; ?12345678910class A{public:A(int i…

Linux下压缩某个文件夹(文件夹打包)

为什么80%的码农都做不了架构师&#xff1f;>>> tar -zcvf /home/xahot.tar.gz /xahot tar -zcvf 打包后生成的文件名全路径 要打包的目录 例子&#xff1a;把/xahot文件夹打包后生成一个/home/xahot.tar.gz的文件。 zip 压缩方法&#xff1a; 压缩当前的文件夹 zi…

GoJS 使用笔记

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 作为商业软件&#xff0c;GoJs很容易使用&#xff0c;文档也很完备&#xff0c;不过项目中没有时间系统地按照文档学习&…

Android学习笔记:TabHost 和 FragmentTabHost

2019独角兽企业重金招聘Python工程师标准>>> Android学习笔记&#xff1a;TabHost 和 FragmentTabHostTabHost命名空间&#xff1a;android.widget.TabHost初始化函数&#xff08;必须在addTab之前调用&#xff09;&#xff1a;setup(); 包含两个子元素&#xff1a;…

PostgreSQL VACUUM 之深入浅出 (二)

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 AUTOVACUUM AUTOVACUUM 简介 PostgreSQL 提供了 AUTOVACUUM 的机制。 autovacuum 不仅会自动进行 VACUUM&#xff0c;也…

分布式概念与协议

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 分布式协议 分布式理论概念 1. 分布式数据一致性 分布式数据一致性&#xff0c;指的是数据在多个副本中存储时&#xff…

java Web监听器导图详解

监听器是JAVA Web开发中很重要的内容&#xff0c;其中涉及到的知识&#xff0c;可以参考下面导图&#xff1a; Web监听器 1 什么是web监听器&#xff1f; web监听器是一种Servlet中的特殊的类&#xff0c;它们能帮助开发者监听web中的特定事件&#xff0c;比如ServletContext,H…

Linux C/C++ UDP Socket 网络通信

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 昨晚 Vv 让我给她讲讲网络编程&#xff0c;于是我就傻乎乎的带她入了门… 以下内容为讲课时制作的笔记&#xff5e; 1. sock…

strtok和strtok_r

strtok和strtok_r原型&#xff1a;char *strtok(char *s, char *delim); 功能&#xff1a;分解字符串为一组字符串。s为要分解的字符串&#xff0c;delim为分隔符字符串。 说明&#xff1a;首次调用时&#xff0c;s指向要分解的字符串&#xff0c;之后再次调用要把s设成NULL。 …

Django ORM

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 目录* Django ORM ORM实操之数据库迁移 ORM实操之字段的修改 ORM实操之数据的增删改查 数据库同步 ORM创建表关系 Dja…

分享25个高质量的移动设备wordpress主题(Mobile theme)

日期&#xff1a;2012-9-10 来源&#xff1a;GBin1.com wordpress毋庸置疑是占有量最大的博客管理系统。提供强大的功能和使用的主题及其自定义模块。随着移动互联网的发展&#xff0c;更多的人开始使用移动设备访问互联网&#xff0c;为了更好的迎合用户的需要&#xff0c;我…

.NET NPOI导出Excel详解

http://www.cnblogs.com/yinrq/p/5590970.html .NET NPOI导出Excel详解 NPOI&#xff0c;顾名思义&#xff0c;就是POI的.NET版本。那POI又是什么呢&#xff1f;POI是一套用Java写成的库&#xff0c;能够帮助开发者在没有安装微软Office的情况下读写Office的文件。 支持的文件格…

c++隐式类型转换存在的陷阱

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 目录* 目标代码 构造函数定义的隐式类型转换分析a1分析a2分析a3 1|0目标代码 旨在弄懂下面的代码&#xff0c;明确变量a1…

Android中将一个图片切割成多个图片[转]

有种场景&#xff0c;我们想将一个图片切割成多个图片。比如我们在开发一个拼图的游戏&#xff0c;就首先要对图片进行切割。 以下是封装好的两个类&#xff0c;可以实现图片的切割。仅供参考和学习。 一个是ImagePiece类&#xff0c;此类保存了一个Bitmap对象和一个标识图片的…

并行开发 —— 第六篇 异步编程模型

在.net里面异步编程模型由来已久&#xff0c;相信大家也知道Begin/End异步模式和事件异步模式&#xff0c;在task出现以后&#xff0c;这些东西都可以被task包装 起来&#xff0c;可能有人会问&#xff0c;这样做有什么好处&#xff0c;下面一一道来。 一&#xff1a; Begin/En…

C++相关

初始化列表中的初始化顺序1 class Printer{2 public:3 Printer(string name){cout<<name;}4 };5 class Container{6 public:7 Container():b("b"),a("a"){}8 Printer a;9 Printer b; 10 }; 11 12 int main…

Java中的Unsafe在安全领域的一些应用总结和复现

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 目录* 0 前言 1 基本使用 1.1 内存级别修改值1.2 创建对象1.3 创建VM Anonymous Class 2 利用姿势 2.1 修改值以关闭RASP等…