Spring Framework Environment抽象

好的,各位观众老爷,各位技术大咖,还有各位和我一样在代码海洋里挣扎的小伙伴们,今天咱们来聊一个Spring Framework里“闷骚”但又极其重要的家伙——Environment抽象。

先别急着打哈欠,我知道“抽象”这两个字一出来,很多人就开始犯困。但信我,这玩意儿绝对值得你花时间搞清楚,因为它就像是Spring王国里的情报局长,掌握着各种机密信息,能让你在配置和应用中游刃有余。?

一、啥是Environment?别跟我扯抽象概念!

咱们先别急着啃那些官方文档里晦涩难懂的定义。用大白话说,Environment就是一个接口,它代表着应用程序运行时的环境。这个环境里包含了各种各样的属性,比如:

  • 系统属性 (System Properties): 你电脑的操作系统版本,Java版本,用户名等等。
  • 环境变量 (Environment Variables): 那些你手动配置的,或者系统自动设置的环境变量,比如JAVA_HOME,PATH等等。
  • Profile: Spring里用来区分不同环境的“标签”,比如开发环境(dev),测试环境(test),生产环境(prod)等等。
  • PropertySource: 这是Environment的核心组成部分,它代表着属性的来源,比如properties文件,YAML文件,甚至是数据库。

你可以把Environment想象成一个巨大的“百宝箱”,里面装着各种各样的“宝贝”,这些宝贝就是应用程序运行时需要的各种配置信息。

举个栗子:

假设你的应用程序需要连接数据库,那么数据库的URL,用户名,密码这些信息,就可以放在一个properties文件里,然后通过PropertySource加载到Environment中。

再举个栗子:

你想在开发环境和生产环境中使用不同的配置,就可以定义不同的Profile,然后在不同的环境下激活不同的Profile。

总而言之,Environment的作用就是提供一个统一的接口,让你能够方便地访问和管理应用程序的各种配置信息。

二、Environment接口:长啥样?

光说不练假把式,咱们来看看Environment接口长啥样。打开你的IDE,找到org.springframework.core.env.Environment接口,你会发现它其实很简单:

public interface Environment extends PropertyResolver {

    /**
     * Return the set of profiles explicitly made active for this environment.
     *
     * @see #acceptsProfiles
     */
    String[] getActiveProfiles();

    /**
     * Return the set of profiles to be activated when no active profiles have been specified.
     *
     * @see #acceptsProfiles
     */
    String[] getDefaultProfiles();

    /**
     * Return whether one or more of the given profiles is active or, in the case of no explicit active profiles,
     * whether one or more of the given profiles is included in the set of default profiles.
     *
     * @param profiles the profile(s) to test
     */
    boolean acceptsProfiles(Profiles profiles);

}

可以看到,Environment接口继承了PropertyResolver接口,而PropertyResolver接口定义了获取属性值的方法:

public interface PropertyResolver {

    /**
     * Return whether the given property key is available for resolution.
     *
     * @param key the property name to check
     * @return whether the property key is available for resolution
     */
    boolean containsProperty(String key);

    /**
     * Return the property value associated with the given key,
     * or {@code null} if the key cannot be resolved.
     *
     * @param key the property name to resolve
     * @return the property value or {@code null} if none found
     * @throws IllegalArgumentException if the given key is empty
     * @throws NullPointerException if the given key is null
     * @see #getProperty(String, String)
     * @see #getProperty(String, Class)
     */
    String getProperty(String key);

    /**
     * Return the property value associated with the given key,
     * or the supplied {@code defaultValue} if the key cannot be resolved.
     *
     * @param key the property name to resolve
     * @param defaultValue the default value to return if no value is found
     * @return the property value or {@code defaultValue} if none found
     * @throws IllegalArgumentException if the given key is empty
     * @throws NullPointerException if the given key is null
     * @see #getProperty(String)
     * @see #getProperty(String, Class, Object)
     */
    String getProperty(String key, String defaultValue);

    /**
     * Return the property value associated with the given key,
     * or {@code null} if the key cannot be resolved.
     *
     * @param key the property name to resolve
     * @param targetType the expected type of the property value
     * @return the property value or {@code null} if none found
     * @throws IllegalArgumentException if the given key is empty
     * @throws NullPointerException if the given key is null
     * @see #getProperty(String)
     */
    <T> T getProperty(String key, Class<T> targetType);

    /**
     * Return the property value associated with the given key,
     * or the supplied {@code defaultValue} if the key cannot be resolved.
     *
     * @param key the property name to resolve
     * @param targetType the expected type of the property value
     * @param defaultValue the default value to return if no value is found
     * @return the property value or {@code defaultValue} if none found
     * @throws IllegalArgumentException if the given key is empty
     * @throws NullPointerException if the given key is null
     * @see #getProperty(String, Object)
     */
    <T> T getProperty(String key, Class<T> targetType, T defaultValue);

    /**
     * Resolve the given placeholder using the properties available through this resolver.
     *
     * @param text the String to resolve
     * @return the resolved String
     * @throws IllegalArgumentException if the given text is empty
     * @throws NullPointerException if the given text is null
     * @throws IllegalArgumentException if the placeholder cannot be resolved
     */
    String resolvePlaceholders(String text);

    /**
     * Resolve the given String value recursively, replacing all placeholders with
     * corresponding property values as defined in the current PropertyResolver.
     *
     * @param text the String to resolve
     * @return the resolved String
     * @throws IllegalArgumentException if the given text is empty
     * @throws NullPointerException if the given text is null
     * @throws IllegalArgumentException if the placeholder cannot be resolved
     */
    String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;

}

所以,Environment接口的核心功能就是:

  • 获取激活的Profile (getActiveProfiles()): 告诉你当前哪些Profile是激活的。
  • 获取默认的Profile (getDefaultProfiles()): 告诉你如果没有激活任何Profile,默认使用哪些Profile。
  • 判断是否接受某个Profile (acceptsProfiles()): 判断当前环境是否接受指定的Profile。
  • 获取属性值 (getProperty()): 根据属性名获取属性值,可以指定默认值和类型。
  • 判断属性是否存在 (containsProperty()): 判断是否存在某个属性。
  • 解析占位符 (resolvePlaceholders()resolveRequiredPlaceholders()): 将字符串中的占位符替换为实际的属性值。

三、Environment的实现类:幕后英雄

Environment只是一个接口,真正干活的是它的实现类。Spring Framework提供了几个常用的Environment实现类:

  • StandardEnvironment: 这是最常用的Environment实现类,它会加载系统属性,环境变量,以及配置文件中的属性。
  • ConfigurableEnvironment: 这是Environment接口的一个扩展,提供了更多的配置选项,比如可以添加和移除PropertySource,可以设置激活的Profile等等。StandardEnvironment 就是 ConfigurableEnvironment 的一个实现。
  • AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext: 这两个类是基于注解的Spring容器,它们内部也持有一个ConfigurableEnvironment实例,用来管理配置信息。
  • AbstractEnvironment: 抽象类,实现了 ConfigurableEnvironment 接口,简化了 Environment 实现类的开发。

关系图:

graph TD
    A[Environment] --> B[PropertyResolver]
    A --> C[ConfigurableEnvironment]
    C --> D[AbstractEnvironment]
    D --> E[StandardEnvironment]
    F[AnnotationConfigApplicationContext] --> C
    G[AnnotationConfigWebApplicationContext] --> C

表格总结:

类名 描述
Environment 接口,定义了访问应用程序运行时环境的方法。
PropertyResolver 接口,定义了获取属性值的方法。
ConfigurableEnvironment 接口,扩展了Environment接口,提供了更多的配置选项。
AbstractEnvironment 抽象类,实现了ConfigurableEnvironment接口,简化了Environment实现类的开发。
StandardEnvironment 常用的实现类,会加载系统属性,环境变量,以及配置文件中的属性。
AnnotationConfigApplicationContext 基于注解的Spring容器,内部持有一个ConfigurableEnvironment实例。
AnnotationConfigWebApplicationContext 基于注解的Spring Web容器,内部持有一个ConfigurableEnvironment实例。

四、PropertySource:属性的来源地

PropertySource是Environment的核心组成部分,它代表着属性的来源。Spring Framework提供了多种PropertySource的实现类,可以从不同的来源加载属性:

  • PropertiesPropertySource: 从Properties文件中加载属性。
  • ResourcePropertySource: 从Resource中加载属性,可以是Properties文件,XML文件等等。
  • MapPropertySource: 从Map中加载属性。
  • SystemEnvironmentPropertySource: 从系统环境变量中加载属性。
  • SystemPropertiesPropertySource: 从系统属性中加载属性。
  • CommandLinePropertySource: 从命令行参数中加载属性。
  • JndiPropertySource: 从JNDI中加载属性。

表格总结:

| 类名 | 描述

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注