Spring系列.Environment介面

程式設計師自由之路發表於2021-09-07

Environment 介面介紹

在 Spring 中,Environment 介面主要管理應用程式兩個方面的內容:profile 和 properties。

profile 可以簡單的等同於環境,比如說平時專案中常見的環境有開發(dev)、測試(stg)和生產(prod),Spring 啟動的時候可以設定啟用具體的環境。當然,這個 profile 我們還可以為其賦予很多含義,這個主要看你的業務。比如說,你開發的軟體會交付給客戶A,也會交付給客戶B,那麼這個 profile 也可以定義成客戶的含義

properties 是配置,配置的來源有很多,可以是配置檔案、JVM 的引數、系統的環境變數、JNDI、Sevlet Contxet 引數以及 Map 物件等,使用 Environment 介面,可以方便的獲取這些配置。

Bean Definition Profiles

使用 @Profile

Spring 容器可以根據不同的 profile 配置不同的 Bean。這個特性可以幫助你實現很多靈活的功能,比如:

  • 開發環境使用記憶體資料庫,測試和生產環境才使用關係型資料庫,比如 Mysql 和 Oracle 等
  • 互動給客戶 A 的軟體使用 A 特性,交付給客戶 B 的軟體使用 B 特性
@Configuration
@Profile("development")
public class StandaloneDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .addScript("classpath:com/bank/config/sql/test-data.sql")
            .build();
    }
}

@Configuration
@Profile("production")
public class JndiDataConfig {

    @Bean(destroyMethod="")
    public DataSource dataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
    }
}

對比上面的兩個配置,我們發現 @Profile 非常適合在兩個環境下,Bean 的定義完全不一樣的情況,如果兩個 Bean 的定義是一樣的,只是一些引數不一樣的話,我們完全可以使用配置檔案的方式實現。

@Profile 註解後面的表示式可以是一個簡單的字串,也可以是一個邏輯運算子。@Profile 支援如下的邏輯運算子。

  • !: A logical “not” of the profile
  • &: A logical “and” of the profiles
  • |: A logical “or” of the profiles

說明:

If a @Configuration class is marked with @Profile, all of the @Bean methods and @Import annotations associated with that class are bypassed unless one or more of the specified profiles are active. If a @Component or @Configuration class is marked with @Profile({"p1", "p2"}), that class is not registered or processed unless profiles 'p1' or 'p2' have been activated.

使用 xml 方式配置

<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="development">
        <jdbc:embedded-database id="dataSource">
            <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
            <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
        </jdbc:embedded-database>
    </beans>

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

啟用 profile

1. API 方式

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
// 設定啟用的 profile
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();

2. 命令列方式

-Dspring.profiles.active="profile1,profile2"

3. 配置檔案方式

spring:
  profiles:
    active: dev

預設的 profile

Spring 預設的 profile 是 default,可以通過 Environment 的 API 進行修改。

PropertySource 介面

PropertySource 介面是對任何形式的 key-value 鍵值對的抽象。

@PropertySource

@PropertySource 這個註解的作用是將配置檔案中的鍵值對放入Environment。這個註解的作用和傳統配置方式中的 context:place-hold一致。

@Configuration
@PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
    @Autowired
    Environment env;
    
    @Bean
    public TestBean testBean() {
        TestBean testBean = new TestBean();
        testBean.setName(env.getProperty("testbean.name"));
        return testBean;
    }
}

經過上面這樣的配置,我們就可以使用 ${key} 這種形式來取變數的值。有時如果我們沒配置 key 的值,Spring 會拋異常。這時我們可以使用 ${key:defaultvalue} 這種形式配置預設值

相關文章