20191231 Spring官方文档(Core 1.13-1.14)

1.13。Environment 抽象

Environment接口是集成在容器中的抽象,可以对应用程序环境的两个关键方面进行建模:profileproperties

profile 是仅在给定 profile 处于活动状态时才向容器注册的Bean定义的命名逻辑组。可以将Bean分配给 profile ,无论是以XML定义还是带有注释。Environment对象与 profile 相关的作用是确定当前哪些 profile (如果有)处于活动状态,以及默认情况下哪些 profile (如果有)应处于活动状态。

属性在几乎所有应用程序中都起着重要作用,并且可能源自各种来源:属性文件,JVM系统属性,系统环境变量,JNDI,Servlet上下文参数,Properties对象,Map对象等。Environment对象与属性有关的角色是为用户提供方便的服务界面,用于配置属性源并从中解析属性。

1.13.1。Bean定义 Profiles

使用 @Profile

profile 字符串可以包含简单的 profile 名称(例如production)或 profile 表达式。 profile 表达式允许表达更复杂的配置文件逻辑(例如production & us-east)。概要文件表达式中支持以下运算符:

  • !:逻辑否
  • &:逻辑与
  • |:逻辑或

您不能在不使用括号的情况下混合使用&and |运算符。例如, production & us-east | eu-central不是有效的表达式。它必须表示为 production & (us-east | eu-central)

您可以将@Profile用作元注释,以创建自定义的组合注释。以下示例定义了一个自定义 @Production批注,您可以将其用作@Profile("production")替代品 :

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

如果用@Profile标记一个@Configuration类,则除非一个或多个指定的 profile 处于活动状态,否则将忽略与该类关联的所有@Bean方法和 @Import注释。如果一个@Component@Configuration类标记有@Profile({"p1", "p2"}),则除非已激活 profile “p1”或“p2”,否则该类不会注册或处理。如果给定的配置文件以NOT运算符(!)为前缀,则仅在该 profile 未激活时才注册带注释的元素。例如,给定@Profile({"p1", "!p2"}),如果 profile “p1”处于活动状态或 profile “p2”未处于活动状态,则会进行注册。

@Profile 也可以在方法级别声明为仅包括配置类的一个特定Bean

@Bean方法使用@Profile时,可能会出现特殊情况:对于具有相同Java方法名称的重载@Bean方法(类似于构造函数重载),@Profile需要在所有重载方法上一致声明条件。如果条件不一致,则仅重载方法中第一个声明的条件很重要。因此,@Profile不能用于选择具有特定参数签名的重载方法。在创建时,相同bean的所有工厂方法之间的解析都遵循Spring的构造函数解析算法。

如果要使用不同的 profile 条件定义备用bean,请使用不同的Java方法名称,这些名称通过使用@Bean name属性指向相同的bean名称,如前面的示例所示。如果参数签名都相同(例如,所有变体都具有无参工厂方法),则这是首先在有效Java类中表示这种排列的唯一方法(因为只能有一个特定名称和参数签名的方法)。

XML Bean定义 Profile

XML对应项是<beans>元素的profile属性。

XML对应项不支持前面描述的 profile 表达式。但是,可以通过使用!运算符来取消 profile 。也可以通过嵌套 profile 来应用逻辑“和”,如以下示例所示:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">

    <!-- other bean definitions -->

    <beans profile="production">
        <beans profile="us-east">
            <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
        </beans>
    </beans>
</beans>

在前面的示例中,如果production和 us-east profile 都处于活动状态,则该dataSource bean是公开的。

激活 Profile

最直接的方法是针对通过ApplicationContext Environment API以编程方式进行配置。

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();

还可以通过spring.profiles.active属性声明性地激活配置文件,可以通过系统环境变量,JVM系统属性,web.xml中的servlet上下文参数或作为JNDI中的条目来指定 profile 。在集成测试中,可以通过使用spring-test模块中的@ActiveProfiles注释来声明活动 profile。

可以一次激活多个 profile 。通过编程,您可以为setActiveProfiles()方法提供多个 profile 名称
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");

以声明方式,spring.profiles.active可以接受以逗号分隔的配置文件名称列表
-Dspring.profiles.active="profile1,profile2"

默认Profile

默认的profile为default

您可以通过Environment上的setDefaultProfiles()更改默认的 profile 的名称,或者通过使用spring.profiles.default属性。

1.13.2。PropertySource 抽象

Spring的Environment抽象提供了对属性源可配置层次结构的搜索操作。

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);

在前面的代码片段中,我们看到了一种询问Spring是否为当前环境定义了my-property属性的高级方法。为了回答这个问题,Environment对象在一组PropertySource 对象上执行搜索。PropertySource是对任何键-值对源的简单抽象,Spring的StandardEnvironment 配置有两个PropertySource对象,一个代表JVM系统属性集(System.getProperties()),一个代表系统环境变量集(System.getenv())。

这些默认属性源存在于StandardEnvironment中,供在独立应用程序中使用。StandardServletEnvironment 用其他默认属性源(包括servlet config和servlet context参数)填充。它可以有选择地启用JndiPropertySource。

具体来说,当您使用StandardEnvironment时, 如果运行时存在my-property系统属性或my-property环境变量,则对env.containsProperty("my-property")的调用将返回true 。

执行的搜索是分层的。默认情况下,系统属性优先于环境变量。因此,如果my-property在调用期间在两个地方同时设置了env.getProperty("my-property")属性,则系统属性值将“获胜”并返回。请注意,属性值不会合并,而是会被前面的条目完全覆盖。

对于common StandardServletEnvironment,完整层次结构如下,最高优先级条目位于顶部:

  • ServletConfig参数(如果适用,例如在DispatcherServlet上下文的情况下)
  • ServletContext参数(web.xml上下文参数条目)
  • JNDI环境变量(java:comp/env/条目)
  • JVM系统属性(-D命令行参数)
  • JVM系统环境(操作系统环境变量)

最重要的是,整个机制是可配置的。也许您有一个要集成到此搜索中的自定义属性源。为此,请实现并实例化自己的实例PropertySource并将其添加到当前Environment的PropertySources 集合中。以下示例显示了如何执行此操作:

ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());

在前面的代码中,MyPropertySource已在搜索中添加了最高优先级。如果它包含一个my-property属性,则检测并返回该属性,以支持其他PropertySource的my-property属性。MutablePropertySources API公开了许多方法,这些方法允许对属性源集进行精确操作。

1.13.3。使用@PropertySource

@PropertySource 注解提供便利和声明的机制添加PropertySource 到Spring的Environment。
@PropertySource("classpath:/com/myco/app.properties")

@PropertySource资源位置中存在的所有${..}占位符都是根据已经针对环境注册的一组属性源来解析的
@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")

假设my.placeholder存在于已注册的属性源之一(例如,系统属性或环境变量)中,则占位符将解析为相应的值。如果不是,则default/path用作默认值。如果未指定默认值并且无法解析属性, 则抛出IllegalArgumentException

@PropertySource注释是可重复的,根据Java 8的约定。但是,所有此类@PropertySource批注都需要在同一级别上声明,可以直接在配置类上声明,也可以在同一自定义批注中声明为元批注。不建议将直接注释和元注释混合使用,因为直接注释会有效地覆盖元注释。

1.13.4。声明中的占位符解析

从历史上看,元素中占位符的值只能根据JVM系统属性或环境变量来解析。这已不再是这种情况。由于Environment抽象是在整个容器中集成的,因此很容易通过它路由占位符的解析。这意味着您可以按照自己喜欢的任何方式配置解析过程。您可以更改搜索系统属性和环境变量的优先级,也可以完全删除它们。您还可以根据需要将自己的属性源添加到混合中。

具体而言,无论customer 属性在何处定义,以下语句均有效,只要该属性在Environment中可用:

<beans>
    <import resource="com/bank/service/${customer}-config.xml"/>
</beans>

1.14。注册一个LoadTimeWeaver

LoadTimeWeaver类加载到Java虚拟机(JVM)中时,Spring会使用来动态转换类。

要启用加载时编织,可以将@EnableLoadTimeWeaving添加到您的一个 @Configuration类,如以下示例所示:

@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
}

另外,对于XML配置,可以使用context:load-time-weaver元素:

<beans>
    <context:load-time-weaver/>
</beans>

一旦针对ApplicationContext进行了配置,则ApplicationContext中的任何bean都可以实现LoadTimeWeaverAware,从而接收到对加载时编织器实例的引用。与Spring的JPA支持结合使用时,该功能特别有用, 因为在进行JPA类转换时可能需要进行加载时编织。

posted @ 2019-12-31 08:28  流星<。)#)))≦  阅读(297)  评论(0编辑  收藏  举报