Environment的中文意思是环境,它表示整个spring应用运行时的环境信息,它包含两个关键因素

  • profiles
  • properties

profiles

profiles这个概念相信大家都已经理解了,最常见的就是不同环境下,决定当前spring容器中的不同配置上下文的解决方案。比如针对开发环境、测试环境、生产环境,构建不同的application.properties配置项,这个时候我们可以通过profiles这个属性来决定当前spring应用上下文中生效的配置项。

实际上,通过profiles可以针对bean的配置进行逻辑分组。 简单来说,我们可以通过profiles来针对不同的bean进行逻辑分组,这个分组和bean本身的定义没有任何关系,无论是xml还是注解方式,都可以配置bean属于哪一个profile分组。

当存在多个profile分组时,我们可以指定哪一个profile生效,当然如果不指定,spring会根据默认的profile去执行。我们来通过一个代码演示一下。

ProfileService

创建一个普通的类,代码如下

public class ProfileService {
private String profile; public ProfileService(String profile) { this.profile = profile;
} @Override
public String toString() {
return "ProfileService{" +
"profile='" + profile + '\'' +
'}';
}
}

声明一个配置类

在配置类中,构建两个bean,配置不同的profile。

@Configuration
public class ProfileConfiguration { @Bean
@Profile("dev")
public ProfileService profileServiceDev(){
return new ProfileService("dev");
} @Bean
@Profile("prod")
public ProfileService profileServiceProd(){
return new ProfileService("prod");
}
}

定义测试方法

public class ProfileMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext();
// applicationContext.getEnvironment().setActiveProfiles("prod");
applicationContext.register(ProfileConfiguration.class);
applicationContext.refresh();
System.out.println(applicationContext.getBean(ProfileService.class));
}
}

可以通过很多种方式来激活配置,默认情况下不添加applicationContext.getEnvironment().setActiveProfiles("prod");时,会发现bean没有被装载。添加了之后,会根据当前激活的profiles来决定装载哪个bean。

除此之外,我们还可以在启动参数中增加-Dspring.profiles.active=prod来决定当前激活哪个profile。该属性可以配置在系统环境变量、JVM系统属性、等。

注意配置文件不是单选;可能会同时激活多个配置文件,编程式的使用方法setActiveProfiles(),该方法接收String数组参数,也就是多个配置文件名

applicationContext.getEnvironment().setActiveProfiles("prod","dev");

如果没有任何profile配置被激活,默认的profile将会激活。

默认profile配置文件可以更改,通过环境变量的setDefaultProfiles方法,或者是声明的spring.profiles.default属性值

profiles总结

简单总结一下profiles,通过profiles可以最一组bean进行逻辑分组,这些逻辑分组的bean会根据Environment上下文中配置的激活的profile来进行加载,也就是Environment对于profiles配置来说,它能决定当前激活的是哪个profile配置。

  • 一个profile就是一组Bean定义的逻辑分组。

  • 这个分组,也就 这个profile,被赋予一个命名,就是这个profile名字。

  • 只有当一个profile处于active状态时,它对应的逻辑上组织在一起的这些Bean定义才会被注册到容器中。

  • Bean添加到profile可以通过XML定义方式或者annotation注解方式。

  • Environment对于profile所扮演的角色是用来指定哪些profile是当前活跃的缺省。

Properties

properties的作用就是用来存放属性的,它可以帮我们管理各种配置信息。这个配置的来源可以是properties文件、JVM properties、系统环境变量、或者专门的Properties对象等。

我们来看一下Environment这个接口,它继承了PropertyResolver,这个接口和属性的操作有关,也就是我们可以通过Environment来设置和获得相关属性。

public interface Environment extends PropertyResolver {
String[] getActiveProfiles(); String[] getDefaultProfiles(); /** @deprecated */
@Deprecated
boolean acceptsProfiles(String... var1); boolean acceptsProfiles(Profiles var1);
}

至此,我们可以可以简单的总结Environment的作用,Environment提供了不同的profile配置,而PropertyResolver提供了配置的操作,由此我们可以知道,Spring 容器可以根据不同的profile来获取不同的配置信息,从而实现Spring容器中运行时环境的处理。

environment的应用

  • 在spring boot应用中,修改application.properties配置

    env=default
  • 创建一个Controller进行测试

    @RestController
    public class EnvironementController { @Autowired
    Environment environment; @GetMapping("/env")
    public String env(){
    return environment.getProperty("env");
    }
    }

指定profile属性

在前面的内容中我们介绍了profile和property这两个概念,现在我们来结合使用加深对这两者的理解。

在spring boot应用中,默认的外部化配置是application.properties文件,事实上,除了这个默认的配置文件之外,我们还可以使用springboot中的约定命名格式来实现不同环境的配置

application-profile.properties

当前spring boot应用选择使用哪个properties文件作为上下文环境配置,取决与当前激活的profile。同样,我们可以通过很多种方式来激活,比如在application.properties中增加spring.profiles.active=dev这种方式,也可以在JVM参数中增加该配置来指定生效的配置。

在不指定的情况下,则使用默认的配置文件,简单来说,如果没有显式激活某一个配置文件,那么应用程序就将加载application-default.properties中的属性。

这个功能非常实用,一般的公司里面都会有几套运行环境,比如开发、测试、生产环境,这些环境中会有一些配置信息是不同的,比如服务器地址。那我们需要针对不同的环境使用指定的配置信息,通过这种方式就可以很方便的去解决。

@Value注解的使用

在properties文件中定义的属性,除了可以通过environment的getProperty方法获取之外,spring还提供了@Value注解,

@RestController
public class EnvironementController { @Value("${env}")
private String env; @GetMapping("/env")
public String env(){
return env;
}
}

spring容器在加载一个bean时,当发现这个Bean中有@Value注解时,那么它可以从Environment中将属性值进行注入,如果Environment中没有这个属性,则会报错。

Spring Environment原理设计

结合前面咱们讲过的内容,我们来推测一下Environment的实现原理。

简单演示一下Environment中的配置来源

  • @Value("${java.version}") 获取System.getProperties , 获取系统属性
  • 配置command的jvm参数, -Denvtest=command

基于现有的内容的推导,我们可以画出下面这样一个图。

  • 第一部分是属性定义,这个属性定义可以来自于很多地方,比如application.properties、或者系统环境变量等。
  • 然后根据约定的方式去指定路径或者指定范围去加载这些配置,保存到内存中。
  • 最后,我们可以根据指定的key从缓存中去查找这个值。

下面这个是表示Environment的类关系图,这个类关系图还是非常清晰的体现了Environment的原理。

上述类图的核心API说明如下

  1. Environment接口,继承了PropertyResolver。 PropertyResolver,它主要有两个作用。

    • 通过propertyName属性名获取与之对应的propertValue属性值(getProperty)。

    • ${propertyName:defaultValue}格式的属性占位符,替换为实际的值(resolvePlaceholders)。

  2. PropertyResolver的具体实现类是PropertySourcesPropertyResolver,属性源的解决方案。该类是体系中唯一的完整实现类。它以PropertySources属性源集合(内部持有属性源列表List)为属性值的来源,按序遍历每个PropertySource,获取到一个非null的属性值则返回。

其中,PropertySourcesPropertyResolver中的List,表示不同属性源的来源,它的类关系图如下,表示针对不同数据源的存储。

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Mic带你学架构

如果本篇文章对您有帮助,还请帮忙点个关注和赞,您的坚持是我不断创作的动力。欢迎关注「跟着Mic学架构」公众号公众号获取更多技术干货!

Spring中的Environment外部化配置管理详解的更多相关文章

  1. Spring中@Component注解,@Controller注解详解

    在使用Spring的过程中,为了避免大量使用Bean注入的Xml配置文件,我们会采用Spring提供的自动扫描注入的方式,只需要添加几行自动注入的的配置,便可以完成 Service层,Controll ...

  2. spring中bean标签factory-method和factory-bean)详解工厂方法(factory-method和factory-bean)

    转自:http://blog.sina.com.cn/s/blog_6d3c1ec601019f3j.html A.factory-method The name of a factory metho ...

  3. Spring Boot 启动(二) 配置详解

    Spring Boot 启动(二) 配置详解 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Boot 配置 ...

  4. 【转】angularjs指令中的compile与link函数详解

    这篇文章主要介绍了angularjs指令中的compile与link函数详解,本文同时诉大家complie,pre-link,post-link的用法与区别等内容,需要的朋友可以参考下   通常大家在 ...

  5. angularjs指令中的compile与link函数详解

    这篇文章主要介绍了angularjs指令中的compile与link函数详解,本文同时诉大家complie,pre-link,post-link的用法与区别等内容,需要的朋友可以参考下   通常大家在 ...

  6. (转)java之Spring(IOC)注解装配Bean详解

    java之Spring(IOC)注解装配Bean详解   在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看 ...

  7. 转载 Spring、Spring MVC、MyBatis整合文件配置详解

    Spring.Spring MVC.MyBatis整合文件配置详解   使用SSM框架做了几个小项目了,感觉还不错是时候总结一下了.先总结一下SSM整合的文件配置.其实具体的用法最好还是看官方文档. ...

  8. saltstack自动化运维系列⑤之saltstack的配置管理详解

    saltstack自动化运维系列⑤之saltstack的配置管理详解 配置管理初始化: a.服务端配置vim /etc/salt/master file_roots: base: - /srv/sal ...

  9. Quartz学习——SSMM(Spring+SpringMVC+Mybatis+Mysql)和Quartz集成详解(转)

    通过前面的学习,你可能大致了解了Quartz,本篇博文为你打开学习SSMM+Quartz的旅程!欢迎上车,开始美好的旅程! 本篇是在SSM框架基础上进行的. 参考文章: 1.Quartz学习——Qua ...

随机推荐

  1. 微信小程序base64图片保存到手机相册

    问题:base64图片不能直接用wx.saveImageToPhotosAlbum保存到手机相册 解决: 先用fs.writeFile写入本地文件,再wx.saveImageToPhotosAlbum ...

  2. 使用结构化克隆在 JavaScript 中进行深度复制

    在很长一段时间内,您不得不求助于变通方法和库来创建 JavaScript 值的深层副本.现在js提供 「structuredClone()」 一个用于深度复制的内置函数. 浏览器支持: 浅拷贝 在 J ...

  3. Nginx高级模块学习

    Nginx的rewrite规则 实现url重写一级重定向 使用场景: 1.URL访问跳转,支持开发设计 页面跳转.兼容性支持.展示效果 2.SEO优化 3.维护 后台维护.流量转发等 4.安全 配置语 ...

  4. WebRTC本地选择codec(web本地模拟)

    视频编码后,再进行发送.WebRTC建立视频连接前,可以选择codec.一般来说支持多种codec,以VP8和H264为代表. Codec: 编码译码器,编解码器 示例代码 写一个示例,用户可以在发送 ...

  5. C\C++ IDE 比较以及调试

    C\C++ IDE 比较以及调试 内容概要 这个作业属于哪个课程 2022面向对象程序设计 这个作业要求在哪里 2022面向对象程序设计寒假作业1 这个作业的目标 IDE 选择以及代码调试 作业正文 ...

  6. 安装MySQL到Ubuntu 20.04

    本文的内容主要来自对How To Install MySQL on Ubuntu 20.04的翻译.在根据该文的指导下,我在自己的Ubuntu 20.04.3 LTS版本中安装了MySQL 8. St ...

  7. Golang 通过创建临时结构体实现 struct 内 interface struct 的 json 反序列化

    原文链接 背景 type AData struct { A string `json:"a"` } type BData struct { B string `json:" ...

  8. 随机IP代理插件Scrapy-Proxies

    安装: pip install scrapy_proxies github:   https://github.com/aivarsk/scrapy-proxies scrapy爬虫配置文件setti ...

  9. django之django-debug-toolbar调试工具配置与使用

    外部链接:https://blog.csdn.net/weixin_39198406/article/details/78821677 django-debug-toolbar的作用:进行性能调优,与 ...

  10. PostgreSQL逻辑订阅

    测试环境:PostgreSQL 13.2 1.逻辑订阅简介 由于物理复制只能做到这个集群的复制,不能正对某个对象(表)进行复制,且物理复制的备库只能读,不能写.相反,逻辑订阅同时支持主备库读写,且可以 ...