ssm笔记四(IoC四)

5 篇文章 0 订阅

环境抽象

Environment 接口是容器的抽象集成,它对应用程序环境的两个关键方面建模:profilesproperties

Bean定义Profiles

profiles是bean定义命名的逻辑分组。容器中可以配置多个profile,但需要指定profile才会把这个profile下的分组bean定义注册到容器中。它允许不同环境下注册不同的bean。

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

可以使用!&|连接多个值。

使用XML
<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>

其他bean要在含profile的beans前面定义。可以嵌套。

激活Profile

default为默认激活。可以通过Environment的setDefaultProfiles()或通过 spring.profiles.default 属性来改变默认的profile的名称。

使用ApplicationContext:

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

使用其它方式:可以通过系统环境变量、JVM系统属性、web.xml上下文参数中的 spring.profile.active 声明。测试时可以使用spring-test中的@ActiveProfiles注解。

PropertySource抽象

查找property source。

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

标准环境有两个PropertySource对象:
1、JVM系统属性集 System.getProperties()
2、系统环境变量集 System.getenv()

整合自定义PropertySources:

COnfigurableApplicationContext ctx = new GernericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirse(new MyPropertySource());
使用@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;
	}
}

${…} 表示使用properties的值。

注册LoadTimeWeaver

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

ApplicationContext的附加功能

org.springframework.beans.factory: 提供管理和控制beans的基本功能。
org.springframework.context:扩展了其他功能。(实现了ApplicationContext以及其他接口)

为增加BeanFactory功能,context包还提供了以下功能:
MessageSource 接口:i18n-style。
ResourceLoader 接口:查找URLS和files。
ApplicationEventPublisher 接口:事务发布实现了 ApplicationListener 接口的beans。
HierarchicalBeanFactory 接口:加载多个层次contexts。

MessageSource

package org.springframework.context;

import java.util.Locale;

import org.springframework.lang.Nullable;

public interface MessageSource {
	@Nullable
	String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
	
	String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;

	String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

}

ApplicationContext被加载后,会寻找名为 messageSource 的bean。

Spring提供了两个MessageSource实现,ResourceBundleMessageSourceStaticMessageSource 。两者都实现 HierarchicalMessageSource 以执行嵌套消息传递。StaticMessageSource很少使用,但提供了向源添加消息的编程方法。

<beans>
    <bean id="messageSource"
            class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>format</value>
                <value>exceptions</value>
                <value>windows</value>
            </list>
        </property>
    </bean>
</beans>
# in format.properties
message=Alligators rock!
# in exceptions.properties
argument.required=The {0} argument is required.
public static void main(String[] args) {
	MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
	String message = resources.getMessage("message", null, "Default", Locale.ENGLISH);
	System.out.println(message);
}

输出: Alligators rock!

<beans>

    <!-- this MessageSource is being used in a web application -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="exceptions"/>
    </bean>

    <!-- lets inject the above MessageSource into this POJO -->
    <bean id="example" class="com.something.Example">
        <property name="messages" ref="messageSource"/>
    </bean>

</beans>
public class Example {

    private MessageSource messages;

    public void setMessages(MessageSource messages) {
        this.messages = messages;
    }

    public void execute() {
        String message = this.messages.getMessage("argument.required",
            new Object [] {"userDao"}, "Required", Locale.ENGLISH);
        System.out.println(message);
    }
}

调用execute()输出:The userDao argument is required.

标准和自定义事件

事件处理通过 ApplicationEvent 类和 ApplicationListener 接口实现。

事件:
ContextRefreshedEvent
ContextStartedEvent
ContextStoppedEvent
ContextClosedEvent
RequestHandleEvent
ServletRequestHandleEvent

发布自定义ApplicationEvent时,需要调用 ApplicationEventPublisherpublishEvent() 方法,这可以靠一个实现 ApplicationEventPublisherAware 接口以及注册为bean的类实现。

public class BlackListEvent extends ApplicationEvent {

    private final String address;
    private final String content;

    public BlackListEvent(Object source, String address, String content) {
        super(source);
        this.address = address;
        this.content = content;
    }

    // accessor and other methods...
}
public class EmailService implements ApplicationEventPublisherAware {

    private List<String> blackList;
    private ApplicationEventPublisher publisher;

    public void setBlackList(List<String> blackList) {
        this.blackList = blackList;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendEmail(String address, String content) {
        if (blackList.contains(address)) {
            publisher.publishEvent(new BlackListEvent(this, address, content));
            return;
        }
        // send email...
    }
}

要接收自定义ApplicationEvent,可以创建一个实现 ApplicationListener 的类,并将其注册为Spring bean。

public class BlackListNotifier implements ApplicationListener<BlackListEvent> {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    public void onApplicationEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
}
<bean id="emailService" class="example.EmailService">
    <property name="blackList">
        <list>
            <value>known.spammer@example.org</value>
            <value>known.hacker@example.org</value>
            <value>john.doe@example.org</value>
        </list>
    </property>
</bean>

<bean id="blackListNotifier" class="example.BlackListNotifier">
    <property name="notificationAddress" value="blacklist@example.org"/>
</bean>
基于注解的事件监听

@EventListener,BlackListNotifier可以写成以下形式:

public class BlackListNotifier {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    @EventListener
    public void processBlackListEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
}

可以监听多个事件。

@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
    // ...
}

可以通过使用定义SpEL表达式的注释的condition属性添加额外的运行时筛选。

@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlackListEvent(BlackListEvent blEvent) {
    // notify appropriate parties via notificationAddress...
}

事件SpEL可用元数据。
在这里插入图片描述

如果处理一个事件后需要发布另一个事件,可以返回另一个事件。也可以是事件集合。

@EventListener
public ListUpdateEvent handleBlackListEvent(BlackListEvent event) {
    // notify appropriate parties via notificationAddress and
    // then publish a ListUpdateEvent...
}
异步监听器

使用 @Async

@EventListener
@Async
public void processBlackListEvent(BlackListEvent event) {
    // BlackListEvent is processed in a separate thread
}

不能返回其他事件,如果需要,注入 ApplicationEventPublisher 手动发布。

排序监听器

使用 @Order

@EventListener
@Order(42)
public void processBlackListEvent(BlackListEvent event) {
    // notify appropriate parties via notificationAddress...
}
通用事件

使用泛型定义事件结构。

@EventListener
public void onPersonCreated(EntityCreatedEvent<Person> event) {
    // ...
}

可以实现 ResolvableTypeProvider 来指导框架超越运行时环境提供的功能。

public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {

    public EntityCreatedEvent(T entity) {
        super(entity);
    }

    @Override
    public ResolvableType getResolvableType() {
        return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource()));
    }
}

Web Applications

可以使用 ContextLoader 等以声明方式创建ApplicationContext。也可以使用ApplicationContext的实现类。

使用 ContextLoaderListener 注册ApplicationContext。

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值