天天看點

008-Spring Ioc 環境與配置@ProfileEnvironment對象擷取配置資訊

@Profile

很多情況下,我們的配置跟需要部署的環境是有關系的,比如我們的資料庫連接配接位址、使用者、密碼等,各個環境是不一樣的,即便我們通過配置檔案加載,但不同的環境依然需要修改之後部署,通過@Profile注解可以将這些環境的配置分開,而且不用重複修改編碼。

@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");
    }
}
           

預設配置檔案

@Configuration
@Profile("default")
public class DefaultDataConfig {

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

以上是@Profile注釋類的情況,@Profile還是注釋方法

為了簡化示例,我們來定義一個K類

package com.yyoo.boot.bean;

public class K {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

           
package com.yyoo.boot.config;

import com.yyoo.boot.bean.K;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("dev")
public class DevConfig {

    @Bean
    public K getK(){
        return new K("開發環境");
    }

}

           
package com.yyoo.boot.config;

import com.yyoo.boot.bean.K;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("test")
public class TestConfig {

    @Bean
    public K getK(){
        return new K("測試環境");
    }

}

           
package com.yyoo.boot.annotation;

import com.yyoo.boot.bean.K;
import com.yyoo.boot.config.AppConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Demo11 {

    @Test
    public void test(){

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        K k = context.getBean(K.class);
        System.out.println(k.getName());

    }

}

           
如此執行後會報錯,因為我們沒有在程式中指定環境,我們也沒有定義預設的profile。我們需要applicationContext的setActiveProfiles方法或者-Dspring.profiles.active來設定環境啟動。
package com.yyoo.boot.annotation;

import com.yyoo.boot.bean.K;
import com.yyoo.boot.config.AppConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Demo11 {

    @Test
    public void test(){

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.getEnvironment().setActiveProfiles("dev");
        context.register(AppConfig.class);
        context.refresh();

        K k = context.getBean(K.class);
        System.out.println(k.getName());

    }

}

           
@Import可以引入其他@Configuration類,來合并配置,最後隻要注冊對應的一個配置類即可
setActiveProfiles可以傳入多個,但我們的邏輯就是其中一個就行了。如果我們加上dev和test一起,那咱們的@Profile就沒有意義了。
注意寫法,AppConfig需要使用register方法注冊,而且最後需要refresh,否則都會報錯。
關于@Profile我們先了解到這兒,後續我們Spring boot + maven的時候我們在來深入講解@Profile與maven配置。(相關連結maven與spring的profile整合)

@Profile允許更複雜的邏輯判斷

  • !:配置檔案的邏輯“非”
  • &:配置檔案的邏輯“與”
  • |:配置檔案的邏輯“或”
注意必要的情況下要是有小括号來保證你的邏輯正确。

Environment對象擷取配置資訊

package com.yyoo.boot.annotation;

import com.yyoo.boot.config.AppConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

public class Demo12 {

    @Test
    public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        ConfigurableEnvironment environment = context.getEnvironment();
        environment.setActiveProfiles("dev");
        context.register(AppConfig.class);
        context.refresh();

        System.out.println(environment);
        System.out.println(environment.getProperty("JAVA_HOME"));// 注意Key值的大小寫
        System.out.println(environment.getProperty("Path"));// 注意Key值的大小寫
    }

}

           
執行後你會發現我們程式中并無配置JAVA_HOME和Path,但能列印出來,因為我們在安裝jdk的時候配置了對應的系統環境變量。
這意味着我們通過Environment類可以擷取對應的系統配置

Environment繼承結構圖如下

008-Spring Ioc 環境與配置@ProfileEnvironment對象擷取配置資訊
我們示例中實際上是StandardEnvironment。

StandardServletEnvironment,完整的層次結構如下

  1. ServletConfig 參數(如果适用 - 例如,在DispatcherServlet上下文的情況下)
  2. ServletContext 參數(web.xml 上下文參數條目)
  3. JNDI 環境變量(java:comp/env/條目)
  4. JVM 系統屬性(-D指令行參數)
  5. JVM系統環境(作業系統環境變量)

使用@PropertySource添加自定義配置

package com.yyoo.boot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;

@Configuration
@Import({DevConfig.class,TestConfig.class})
@PropertySource({"classpath:test.properties"})
public class AppConfig {


}
           
@PropertySource添加了一個resource目錄的test.properties配置檔案

配置檔案

my.test.name = Hello Spring
JAVA_HOME = rewrite
           

修改K類如下

package com.yyoo.boot.bean;

import org.springframework.beans.factory.annotation.Value;

public class K {

    private String name;

    @Value("${JAVA_HOME}")
    private String javaHome;

    public K() {
    }

    public K(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getJavaHome() {
        return javaHome;
    }

    public void setJavaHome(String javaHome) {
        this.javaHome = javaHome;
    }
}

           
@Value可以讀取配置,但如果對應的key值不存在,項目啟動将會報錯。而且這個注解在任意類中可以使用,如果濫用對導緻代碼中有大量的@Value對應的key值,如果某個key值使用很多,當這個key值修改名稱的時候就是個災難。
@Value接收 , 占 位 符 , 執 行 時 會 替 換 為 響 應 k e y 對 應 的 值 , 如 果 不 是 有 {},占位符,執行時會替換為響應key對應的值,如果不是有 ,占位符,執行時會替換為響應key對應的值,如果不是有{},直接使用字元串,那麼其注解的屬性對應的值就是該字元串本身,這并沒有什麼意義。

Demo

package com.yyoo.boot.annotation;

import com.yyoo.boot.bean.K;
import com.yyoo.boot.config.AppConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

public class Demo12 {

    @Test
    public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        ConfigurableEnvironment environment = context.getEnvironment();
        environment.setActiveProfiles("dev");
        context.register(AppConfig.class);
        context.refresh();

        System.out.println(environment);
        System.out.println(environment.getProperty("my.test.name"));
        System.out.println(environment.getProperty("JAVA_HOME"));// 注意Key值的大小寫
        System.out.println(environment.getProperty("Path"));// 注意Key值的大小寫

        K k = context.getBean(K.class);
        System.out.println(k.getJavaHome());

    }

}

           

執行結果分析

執行後你會發現,自定義配置檔案中my.test.name屬性列印出來了,但自定義的JAVA_HOME并沒有被覆寫。系統變量也能通過@Value注解注入到對應的bean中。

上一篇:007-Spring IoC 基于Java程式設計的配置

下一篇:009-Spring IoC 國際化(i18n)