Environment中文意思是环境,代表了整个spring应用运行时的环境信息。它包含两个关键因素:profilespropertiesprofilesprofiles。相信大家都了解profiles的概念。最常见的是在不同的环境中,确定当前spring容器中不同配置上下文的解决方案。比如为开发环境、测试环境、生产环境构建不同的application.properties配置项。这时候我们可以通过profiles属性来判断当前spring应用上下文中生效的配置项。事实上,配置文件可用于对bean配置进行逻辑分组。简单来说,我们可以通过配置文件对不同的bean进行逻辑分组。这种分组与bean本身的定义无关。不管是XML还是注解,都可以配置bean属于哪个profile组。当有多个配置文件组时,我们可以指定哪个配置文件生效。当然,如果不指定,spring会按照默认的profile执行。让我们用代码来演示它。ProfileService创建一个普通类,代码如下publicclassProfileService{privateStringprofile;publicProfileService(Stringprofile){this.profile=profile;}@OverridepublicStringtoString(){return"ProfileService{"+"profile='"+profile+'\''+'}';}}声明一个配置类在配置类中,构建两个bean,配置不同的profile。@ConfigurationpublicclassProfileConfiguration{@Bean@Profile("dev")publicProfileServiceprofileServiceDev(){returnnewProfileService("dev");}@Bean@Profile("prod")publicProfileServiceprofileServiceProd(){returnnewProfileService("prod");}}定义测试方法publicclassProfileMain{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext();//applicationContext.getEnvironment().setActiveProfiles("prod");applicationContext.register(ProfileConfiguration.class);applicationContext.refresh();System.out.println(applicationContext.getBean(ProfileService.class));}}配置可以通过多种方式激活,默认不添加applicationContext.getEnvironment()。setActiveProfiles("prod");,你会发现没有加载bean。添加后,它会根据当前活动的配置文件来决定加载哪个bean。此外,我们还可以在启动参数中加入-Dspring.profiles.active=prod来判断当前激活的是哪个profile。该属性可以在系统环境变量、JVM系统属性等配置,注意配置文件不是单一选择;可能会同时激活多个配置文件,编程使用方法setActiveProfiles(),接收一个String数组参数,即多个配置文件名applicationContext.getEnvironment().setActiveProfiles("prod","dev");如果没有激活配置文件配置,将激活默认配置文件。defaultprofile配置文件可以改变,通过环境变量的setDefaultProfiles方法,或者声明的spring.profiles.default属性值profilesSummary简单总结一下profiles,通过profiles可以对一组bean进行逻辑分组,这些逻辑分组beans会根据Environment上下文中配置的activatedprofile进行加载,也就是说,对于profiles配置,Environment可以判断当前激活的是哪个profile配置。配置文件是Bean定义的逻辑分组。这个组,即配置文件,被赋予一个名称,即配置文件名称。只有当配置文件处于活动状态时,其相应的逻辑组织的bean定义才会注册到容器中。Beans可以通过XML定义或者annotation注解的方式添加到profile中。环境对配置文件的作用是指定默认情况下哪些配置文件当前处于活动状态。Properties属性的作用是存储属性,可以帮助我们管理各种配置信息。这个配置的来源可以是properties文件,JVM属性,系统环境变量,或者专门的Properties对象等等。我们来看一下Environment接口,它继承了PropertyResolver。这个接口是和属性的操作相关的,也就是我们可以通过Environment来设置和获取相关的属性。publicinterfaceEnvironmentextendsPropertyResolver{String[]getActiveProfiles();字符串[]getDefaultProfiles();/**@deprecated*/@DeprecatedbooleanacceptsProfiles(String...var1);booleanacceptsProfiles(Profilesvar1);}至此,我们可以简单的总结一下Environment的作用。Environment提供不同的profile配置,PropertyResolver提供配置操作。由此我们可以知道,Spring容器可以根据不同的profile获取不同的配置信息,从而实现Spring容器。处理运行时环境。环境的应用在springboot应用中,修改application.properties配置env=default创建一个Controller用于测试@RestControllerpublicclassEnvironmentController{@AutowiredEnvironment环境;@GetMapping("/env")publicStringenv(){returnenvironment.getProperty("env");}}指定profile属性在前面的内容中,我们介绍了profile和property这两个概念。现在让我们一起使用它们来加深我们的理解。在springboot应用中,默认的外部配置是application.properties文件。其实除了这个默认的配置文件,我们还可以使用springboot中约定好的命名格式来配置不同环境下的application-profile.properties当前springboot应用选择使用哪个properties文件作为context环境配置,取决于当前活动的配置文件。同样,我们可以通过多种方式激活,比如在application.properties中添加spring.profiles.active=dev,或者在JVM参数中添加这个配置,指定生效的配置。如果未指定,则使用默认配置文件。简单地说,如果一个配置文件没有明确激活,应用程序将加载application-default.properties中的属性。这个功能非常实用。一般企业都会有几套运行环境,比如开发、测试、生产环境。这些环境中的一些配置信息会有所不同,比如服务器地址。那么我们需要针对不同的环境使用指定的配置信息,通过这种方式就可以轻松解决。@Value注释的使用定义了属性文件中的属性。除了通过环境的getProperty方法获取,spring还提供了@Value注解,@RestControllerpublicclassEnvironmentController{@Value("${env}")privateStringenv;@GetMapping("/env")publicStringenv(){返回环境;}}spring容器在加载bean时,发现bean中有@Value注解时,可以从Environment中注入属性值,如果Environment中没有这个属性,就会报错。SpringEnvironment的原理设计结合前面所说的,我们来推测一下Environment的实现原理。简单演示Environment@Value("${java.version}")获取System.getProperties中的配置源,获取系统属性配置命令的jvm参数,-Denvtest=command基于已有内容推导,我们可以画出下面这样的图。第一部分是属性定义,可以来自很多地方,比如application.properties,或者系统环境变量。然后指定路径或者指定范围按照约定的方式加载这些配置并保存在内存中。最后我们可以根据指定的key从缓存中查找这个值。下面是表示环境的类图。这个类图还是很清楚的体现了Environment的原理。上面类图的核心API描述如下Environment接口,它继承了PropertyResolver。PropertyResolver,它主要有两个功能。通过propertyName属性名获取对应的propertyValue属性值(getProperty)。将${propertyName:defaultValue}格式的属性占位符替换为实际值(resolvePlaceholders)。PropertyResolver的具体实现类是PropertySourcesPropertyResolver,属性源的解析。该类是系统中唯一完整的实现类。它使用PropertySources属性源集合(内部保存属性源列表List
