之前提到Spring中IOC容器的體現其實就是BeanFactory和ApplicationContext的實現。為增強BeanFactory功能,ApplicationContext接口提供了些其他的功能:
- 通過MessageSource接口以i18n方式訪問消息;
- 通過ResourceLoader接口訪問資源,比如URLs和文件;
- 實現ApplicationListener接口 事件發布給bean,通過ApplicationEventPublisher接口;
- 加載多個(分層的)上下文,通過HierarchicalBeanFactory接口,允許每個專注一個特殊層,比如應用程序的web層。
下面來介紹下這些功能。
MessageSource
MessageSource接口主要用於國際化。
事件機制
在某些關鍵點,Spring容器會發布一些ApplicationEvent事件,注冊在容器中的ApplicationListener能監聽到這些事件。這種是典型的觀察者模式。 Spring提供了一系列標准事件:
- ContextRefreshedEvent:調用refresh()之后;
- ContextStartedEvent:調用start()方法;
- ContextStoppedEvent:調用context的stop()方法;
- ContextClosedEvent:調用context的close()方法后促發;
下面展示下使用Spring事件機制的過程(Spring的事件機制可以實現類似EventBus的功能)。
step1:定義事件
public class BlackListEvent extends ApplicationEvent {
private final String address;
private final String test;
public BlackListEvent(Object source, String address, String test) {
super(source);
this.address = address;
this.test = test;
}
// accessor and other methods...
}
step2:發布事件
事件發布通常的做法是定義一個Bean,讓這個Bean實現ApplicationEventPublisherAware接口,讓這個Bean准們負責事件發布工作。
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 text) {
//這邊用來發布事件
if (blackList.contains(address)) {
BlackListEvent event = new BlackListEvent(this, address, text);
publisher.publishEvent(event);
return;
}
// send email...
}
}
step3:接收事件
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...
}
}
事件發布器的publishEvent()方法默認是一個同步方法,所以這個方法會一直阻塞直到所有注冊到容器中的ApplicationListenner執行完畢(當然可以配置線程池,實現異步模式)。
基於注解的ApplicationListener
注意,分發器還是要自己實現。
@Component
public class BlackListNotifierAnnotaion {
//Order的值越小,越先被調用
//基於注解@EventListener的Listenner永遠先與傳統的實現ApplicationListener接口的Listenner被調用。
@Order(Integer.MIN_VALUE+1)
@EventListener(classes = {BlackListEvent.class,ContextRefreshedEvent.class})
public void processEvent(ApplicationEvent event){
if(event instanceof BlackListEvent){
System.out.println("收到BlackListEvent1");
}
if(event instanceof ContextRefreshedEvent){
System.out.println("收到ContextRefreshedEvent1");
}
}
@Order(Integer.MIN_VALUE+2)
@EventListener(classes = {BlackListEvent.class,ContextRefreshedEvent.class})
public void processEvent2(ApplicationEvent event){
if(event instanceof BlackListEvent){
System.out.println("收到BlackListEvent2");
}
if(event instanceof ContextRefreshedEvent){
System.out.println("收到ContextRefreshedEvent2");
}
}
}
異步ApplicationListener
@Component
public class BlackListNotifierAnnotaion {
//Order的值越小,越先被調用
//基於注解@EventListener的Listenner永遠先與傳統的實現ApplicationListener接口的Listenner被調用。
@Order(Integer.MIN_VALUE+1)
@Async("線程池name")
@EventListener(classes = {BlackListEvent.class,ContextRefreshedEvent.class})
public void processEvent(ApplicationEvent event){
if(event instanceof BlackListEvent){
System.out.println("收到BlackListEvent1");
}
if(event instanceof ContextRefreshedEvent){
System.out.println("收到ContextRefreshedEvent1");
}
}
}