IoC容器篇(十四)——环境抽象、注册LoadTimeWeaver

目录

环境抽象

1.Bean定义profiles

2.属性源抽象

3.@PropertySource

4.语句中的占位符解析

注册LoadTimeWeaver

翻译源:Spring官方文档


 

环境抽象

Environment是一个集成进容器的抽象,塑造了应用环境的两个关键方面:profiles与properties。

一个profile是一个命名的逻辑相关的bean定义组,组中的bean定义只有在给定的profile被激活之后才会在容器中注册。

beans通过xml或注解的方法赋值给profile。

Environment在与profile的关系中扮演的角色是决定哪些profiles当前需要激活,哪些profies默认被激活。

Environment在与properties的关系中扮演的角色是为用户提供一个用于配置属性源与解析属性的服务接口。

 

1.Bean定义profiles

Bean定义切面是允许在不同环境下注册不同beans的容器机制。

@Profile

将bean定义划分进profile

@Configuration
@Profile("A")
public class AConfig {

    @Bean(destroyMethod="")
    public Foo foo() {
        return new FooA();
    }
}
@Configuration
@Profile("B")
public class BConfig {

    @Bean(destroyMethod="")
    public Foo foo() {
        return new FooB();
    }
}

note:AConfig下的所有bean全部划入profile A,BConfig下的所有bean全部划入profile B。

note:当profileA激活时,AConfig可以被注册,当profileB激活时,BConfig可以被注册。

ps:当@Profile注解@Configuration类时,此类下的所有bean定义以及此类使用@Import注解关联的bean定义全部划入此profile。

ps:@Profile可传入多个属性值,eg:@Profile({"a", "b"}),此时当a或b被激活时,注解的bean定义可用。

ps:@Profile("!a"),表示a没有被激活时,注解的bean可用。

ps:@Profile可以注解在单个@Bean方法上,表示将这一个bean划入给定的profile。

@Profile作为元注解构建组合注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("production")
public @interface Production {
}

note:构建组合注解@Produnction。

@Profile可以用来重载具有相同名字的@Bean方法。(类似于构造器重载。)

一个@Profile条件需要一致地声明在所有重载地方法上。

如果条件不一致,只有在重载方法上第一次声明的条件才会起作用。

因此,@Profile不能用于从重载方法中选出带有特定参数签名的方法。

如果想要使用不同的profile条件定义可选beans,通过@Bean注解属性使用不同的方法名指向相同的bean。

XML定义profiles

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

ps:通过设置不同的xml配置文件的<beans>的profile属性,进而将不同xml文件下的beans划分进不同的profile。

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

note:在一个xml文件下使用嵌入的多个<beans>元素,来实现profile。

ps:<beans>只能放在xml文件的末尾处。

激活profile

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

note:通过编程方式直接激活development profile。

ps:可以传入多个参数,同时激活多个profile:ctx.getEnvironment().setActiveProfiles("profile1", "profile2");

可以通过设置spring.profiles.active属性,激活指定的profile。

spring.profiles.active可以设置在系统环境变量中,可以设置在jvm属性中,可以设置在web.xml的servlet context参数中,甚至可以作为入口设置在JNDI中。

在集成测试时,可以通过spring-test模块里@ActiveProfile注解设置被激活的profile。

设置属性时,可以通过逗号分隔的profile名称列表激活多个profile:
-Dspring.profiles.active="profile1,profile2"

默认profile

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

ps:default profile是默认被激活的profile。

ps:一旦有其他profile被激活,默认profile就不会激活。

ps:可以使用Environment的setDefaultProfiles()修改默认profile的名称

ps:也可以使用spring.profiles.default属性修改默认profile的名称

2.属性源抽象

ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
boolean containsFoo = env.containsProperty("foo");

note:判断当前环境中是否存在foo属性。

note:Envrionment对一个PropertySource对象集合执行了一个搜索操作。

Environment提供了对属性源配置的继承体系的搜索操作。

PropertySource是对一个任意键值对源的一个简单抽象。

Spring的StandardEnvironment被配置了两个PropertySource对象,一个对象表示jvm属性集合(System.getProperties()),一个表示系统环境变量集合(System.getenv())。

StandardEnvironment表示用于独立应用的默认的属性源。

StandServletEnvironment除了默认属性源,还将servlet config与servlet context paraments作为默认属性源填入。

可以将JnidPropertySource可选添加。

搜索属性的优先顺序:

  • ServletConfig parameters
  • ServletContext parameters
  • JNDI environment variable
  • JVM system properties
  • JVM system environment
ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());

note:手动添加新的属性源。

ps:MutablePropertySources API 提供了一些用于精确操作属性源集合的操作。

3.@PropertySource

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

note:将app.properties中的testbean.name设置为testBean的name属性。

ps:@PropertySource提供将PropertySource添加进Environment的便捷机制。

ps:@PropertySource注解是可重复注解。

ps:@PropertySource可以作为元注解构建组合注解。

ps:多个@PropertySource同时注解时,直接注解有更高的优先级。

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

note:从当前系统的Environment寻找my.placeholder属性,如果找到便使用,如果没找到,使用设置的default/path。

4.语句中的占位符解析

Environment抽象现在已经被集成到了整个容器中,所以控制解析过程变得简单。

这意味着可以根据开发者的要求修改解析过程:改变寻找属性时使用的属性源的优先级,移除属性源,添加新属性源。

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

ps:只要占位符中引用的属性存在于Environment中,无论占位符引用的属性定义在哪个属性源中,都能够完成解析。

注册LoadTimeWeaver

LoadTimeWeaver用于当类被载入jvm时,动态转化类。

@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
}
<beans>
    <context:load-time-weaver/>
</beans>

note:使用java配置或xml配置启用载入时织入。

ApplicationContext中实现了LoadTimeWeaverAware接口的bean可以接收一个指向载入时织入实例的引用。

在Spring的JPA支持中,载入时织入对于JPA类转化是必要的。


翻译源:Spring官方文档

猜你喜欢

转载自blog.csdn.net/qq_32165041/article/details/82619856