天天看点

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)