spring学习(十一)——spring官方文档阅读(5.0.7)——环境抽象

环境抽象

profile允许在不同的环境下注册使用不同的bean,举个例子,我们在生产环境使用JNDI配置数据源,在测试环境使用in-memory的数据源,我们先实现这两种方法:

in-memory的datasource:

@Bean
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseType.HSQL)
        .addScript("my-schema.sql")
        .addScript("my-test-data.sql")
        .build();
}

JNDI的datasource:

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

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

在继续介绍如何使用前,我们先来看看@Profile注解,和@Component一样,@Profile也是元注解,如果在@Configuration上使用@Profile,所有的@Bean方法和@Import注解在指定的profiles启动的情况下才会启用,特别的,!号表示不启用,例如@Profile({"p1", "!p2"})表示启用p1,不启用p2的情况

@Profile也可以用于方法上:

@Configuration
public class AppConfig {

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

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

可以在xml中使用<beans>标签的profile属性,上述两个例子可以在xml中如下定义,可以达到相同的效果:

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

    <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"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">

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

接下来我们看看设定当前运行环境(拿上面例子来说,指定是development或是production),我们可以通过ApplicationContext中的Environment的API指定当前运行环境:

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

在springboot中,可以在配置文件中通过spring.profiles.active指定环境,可以一次指定多套运行环境:

ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
spring.profiles.active="profile1,profile2"

@Profile的值为default的类表示在没有指定任何环境的情况下使用,任何一个环境被指定都不会被使用

 

PropertySource abstraction

Environment类提供了在配置层次结构中搜索property sources(我们自己注册的)的功能:

ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
boolean containsFoo = env.containsProperty("foo");
System.out.println("Does my environment contain the 'foo' property? " + containsFoo);

在上述例子,Spring会询问在当前环境中是否存在foo属性,Environment对象会查询PropertySource对象(该对象以键值对的形式存储Property),StandardEnvironment配置了两种PropertySource对象——一种包含JVM系统属性,一种包含系统环境变量,系统属性比环境变量优先级高

StandardServletEnvironment 除了上述两种PropertySource对象外,还包括servlet config和servlet context

如果我们想加入自定义的PropertySource对象,可以使用addFirst函数:

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

在上述例子中,MyPropertySource具有最高的优先级

 

@PropertySource

@PropertySource注解可以很方便的添加PropertySource到Spring的Environment对象,举个例子

在运行时,/com/myco/app.properties的键值对将会被添加到Environment对象中。app.properties包含了键值对testbean.name=myTestBean,下列例子setName函数的参数值将为myTestBean,

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

可以在@PropertySource使用占位符,这些占位符根据已经注册的环境属性源进行解析

@Configuration
@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")
public class AppConfig {

    @Autowired
    Environment env;

    @Bean
    public TestBean testBean() {
        TestBean testBean = new TestBean();
        testBean.setName(env.getProperty("testbean.name"));
        return testBean;
    }
}

上述代码中,如果在已经注册的环境属性源中没有找到占位符的值,将默认使用default/path,若没有默认值,则会抛出IllegalArgumentException异常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值