美文网首页
Spring IoC容器之环境抽象

Spring IoC容器之环境抽象

作者: 夏与清风 | 来源:发表于2019-07-19 15:17 被阅读0次

Environment是一个集成到容器中的特殊抽象,它针对应用环境建立了profile和properties。

\bullet profile:包含了多个bean定义的一个逻辑集合,只有当指定的profile倍激活时,其中的bean才会被激活。通过XML定义或通过注解,bean都可以配置到profile中。Environment与profile相关联,然后决定来激活哪个profile或哪个为默认的profile。

\bullet properties:它在应用中有着重要作用,如property文件、JVM系统的property、系统环境变量、JNDI、srevlet上下文参数、Map等。Environment与property相关联,给开发者一个方便的服务接口来配置这些数据源,并正确解析。

1、bean定义的profile

在容器中bean定义的profile是一种允许不同环境注册不同的bean的机制,适用以下场景:

1)解决内存中数据源问题,可以在不同环境中访问不同的数据源,如dev、sit、pre、prd环境等。

2)仅在开发环境中使用一些监视服务。

3)在不同环境中使用不同的bean实现。

如果泛化了一些特殊环境下引用的bean定义,可以将其中指定的bean注入特定的上下文中,而不是注入所有的上下文中。

2、@Profile

@Profile注解允许开发者表示一个组件是否适合在当前环境下进行注册,只有当前的profile被激活时,对应的bean才会被注册到上下文中。

@Configuration

@Profile("dev")

public class DataConfig {

    @Bean

    public DataSource dataSource() {

        return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)

            .addScript("classpath:com/config/sql/schema.sql")

            .addScript("classpath:com/config/sql/test-data.sql").build();

    }

}

@Configuration

@Profile("prd")

public class JndiDataConfig {

    @Bean

    public DataSource dataSource() throws Exception {

        Context ctx =new InitialContext();

        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");

    }

}

@Profile注解可以作为元注解来使用,如下自定义的@Prd注解可以替代@Profile("prd"):

@Profile注解也可以在方法级别使用,还可以声明在包含@Bean注解的方法上。如下:

@Configuration

public class AppConfig {

    @Bean

    @Profile("dev")

    public DataSource dataSource() {

        return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)

            .addScript("classpath:com/config/sql/schema.sql")

            .addScript("classpath:com/config/sql/test-data.sql").build();

    }

    @Bean

    @Profile("prd")

    public DataSource dataSource() throws Exception {

        Context ctx =new InitialContext();

        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");

    }

}

如果配置了@Configuration的类同时也配置了@profile,则所有配置了@Bean注解的方法和@Import注解的类都会被传递为该profile。除非这个profile被激活,否则其中的bean定义都不会被激活。如果配置为@Component或@Configuration的类标记了@profile({"p1","p2"}),那么这个类当且仅当profile为p1或p2时才会被激活。如果某个profile的前缀为“!”,则@profile注解的类只有在当前的profile没被激活时才能生效。如配置为@profile({"p1","!p2"})则注册的行为会在profile为p1或profile为非p2时被激活。

3、XML中定义的profile

在XML中配置<beans/>的profile属性。

<beans profile="dev"

    xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:jdbc="http://www.springframework.org/schema/jdbc"

    xsi:schemaLocation="...">

    <jdbc:embedded-database id="dataSource">

        <jdbc:script location="classpath:com/config/sql/schema.sql">

        <jdbc:script location="classpath:com/config/sql/test-data.sql">

    </jdbc:embedded-database>

</beans>

<beans profile="prd"

    xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:jee="http://www.springframework.org/schema/jee"

    xsi:schemaLocation="...">

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

</beans>

或者通过嵌套<beans>标签来定义:

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:jee="http://www.springframework.org/schema/jee"

    xmlns:jdbc="http://www.springframework.org/schema/jdbc"

    xsi:schemaLocation="...">

    <beans profile="dev">

        <jdbc:embedded-database id="dataSource">

            <jdbc:script location="classpath:com/config/sql/schema.sql">

            <jdbc:script location="classpath:com/config/sql/test-data.sql">

        </jdbc:embedded-database>

    </beans>

    <beans profile="prd">

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

    </beans>

</beans>

4、激活profile

有多种方法来激活一个profile,最直接的方式是通过编程的方式来直接调用Environment API。ApplicationContext中包含以下接口:

AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext();

context.getEnvironment().setActiveProfiles("dev");

context.register(SomeConfig.class,DataConfig.class,PrdDataConfig.class);

context.refresh();

profile还可以通过spring.profiles.active中的属性来指定,可以通过系统环境变量、JVM系统变量、servlet上下文中的参数或JNDI的一个参数来写入。profile的定义并非是互斥关系,开发者可以在同一时间激活多个profile。

context.getEnvironment().setActiveProfiles("dev","sit");

也可以通过spring.profiles.active来指定逗号分隔的多个profile名称。

-Dspring.profiles.active=“profile1,profile2”

5、默认profile

@Configuration

@Profile("default")

public class DataConfig {

    @Bean

    public DataSource dataSource() {

        return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)

            .addScript("classpath:com/config/sql/schema.sql")

            .addScript("classpath:com/config/sql/test-data.sql").build();

    }

}

如果没有其他profile被激活,则以上定义的dataSource将被创建,这种方式是默认情况下提供bean定义的一种方式。一旦任何一个profile被激活,默认的profile将不会被激活。默认的profile的名称可以通过Environment中的setActiveProfiles()或通过spring.profiles.default属性来更改。

6、@PropertySource

@PropertySource注解提供了一种方便的机制将PropertySource添加到spring的Environment中。给定一个文件app.properties包含了key-value对testbean.name=myTestBean,以下代码使用@PropertySource调用testbean.setName()将返回myTestBean。

@Configuration

@PropertySource("classpath:/com/xlws/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注解中如${...}的占位符,都可以被解析为Environment中的属性资源。如下:

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

    }

}

假设my.placeholder是已经注册到Environment中的资源,若有JVM系统属性或环境变量,占位符会解析成对象的值,若没有则default/path会作为默认值。如果没有指定默认值,并且占位符也解析不出来,将会抛出异常IllegalArgumentException。

7、占位符解析

开发者可以任意配置占位符:

1)可以自由调整系统变量和环境变量的优先级。

2)可以额外增加自己的属性源信息。

以下XML配置不关心customer属性在哪里定义,只要这个值在Environment中有效即可:

<beans>

    <import resource="com/xlws/service/${customer}-config.xml" />

</beans>

--参考文献《Srping5开发大全》

相关文章

网友评论

      本文标题:Spring IoC容器之环境抽象

      本文链接:https://www.haomeiwen.com/subject/gclwkctx.html