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官方文档

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在WPF中使用IoC容器可以让代码更加灵活、可扩展和易于维护。常见的IoC容器有Autofac、Unity、StructureMap等。 下面以Autofac为例,介绍如何在WPF中进行IoC容器注册。 1. 安装Autofac NuGet包 在Visual Studio中打开NuGet包管理器控制台,执行以下命令: ``` Install-Package Autofac ``` 2. 创建一个IoC容器 在App.xaml.cs文件中创建一个静态的Autofac容器: ```csharp public partial class App : Application { public static IContainer Container { get; private set; } protected override void OnStartup(StartupEventArgs e) { // 创建一个IoC容器 var builder = new ContainerBuilder(); // 注册依赖关系 builder.RegisterType<MyService>().As<IMyService>(); // 构建容器 Container = builder.Build(); base.OnStartup(e); } } ``` 在这个例子中,我们注册了一个名为MyService的服务,并将其标记为IMyService接口的实现类型。 3. 在应用程序中使用IoC容器 在需要使用服务的地方,我们可以使用容器解析服务的实例。 ```csharp public partial class MainWindow : Window { private readonly IMyService _myService; public MainWindow() { InitializeComponent(); // 通过IoC容器获取MyService的实例 _myService = App.Container.Resolve<IMyService>(); } } ``` 在这个例子中,我们使用IoC容器解析MyService的实例,并将其保存在_myService字段中。这样,在MainWindow类中就可以使用_myService字段调用MyService中的方法了。 通过这种方式,我们可以实现依赖注入,减少代码的耦合性,提高应用程序的可扩展性和易于维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值