1.15. Additional Capabilities of the ApplicationContext
ApplicationContext继承了很多接口,所以它还提供以下能力:
- 国际化。Access to messages in i18n-style, through the MessageSource interface.
- 资源访问。Access to resources, such as URLs and files, through the ResourceLoader interface.
- 事件发布。Event publication, namely to beans that implement the ApplicationListener interface, through the use of the ApplicationEventPublisher interface.
- 多context。Loading of multiple (hierarchical) contexts, letting each be focused on one particular layer, such as the web layer of an application, through the HierarchicalBeanFactory interface.
1.15.1. Internationalization using MessageSource
ApplicationContext提供了国际化能力:
The ApplicationContext interface extends an interface called MessageSource and, therefore, provides internationalization (“i18n”) functionality
具体国际化介绍可以参考下文:
spring学习4-国际化
MessageSource接口提供以下方法:
- String getMessage(String code, Object[] args, String default, Locale loc): The basic method used to retrieve a message from the MessageSource. When no message is found for the specified locale, the default message is used. Any arguments passed in become replacement values, using the MessageFormat functionality provided by the standard library.
- String getMessage(String code, Object[] args, Locale loc): Essentially the same as the previous method but with one difference: No default message can be specified. If the message cannot be found, a NoSuchMessageException is thrown.
- String getMessage(MessageSourceResolvable resolvable, Locale locale): All properties used in the preceding methods are also wrapped in a class named MessageSourceResolvable, which you can use with this method.
Spring ApplicationContext会主动寻找名为MessageSource的bean,如果能找到,就使用这个bean进行国际化;如果找不到,则默认给一个空的DelegatingMessageSource实现。
Spring提供了一些MessageSourcede 的实现,比如ResourceBundleMessageSource。
MessageSource的basename设置方式如下。
xml方式:
<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>
注解方式:
@Configuration
@ComponentScan(basePackages = "examples")
public class AppConfig {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
resourceBundleMessageSource.setBasenames("format", "exceptions", "windows");
return resourceBundleMessageSource;
}
}
exceptions.properties:
# in exceptions.properties
argument.required=The {0} argument is required.
public class Application {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(((AnnotationConfigApplicationContext) context).getBeanFactory());
context.getBean("example", Example.class).execute();
}
}
上述代码的执行结果如下:
The userDao argument is required.
最后,通过按照国际化命名方式配置相应的配置文件,即可实现国际化。
As an alternative to ResourceBundleMessageSource, Spring provides a ReloadableResourceBundleMessageSource class.
1.15.2. Standard and Custom Events
支持事件的发布和订阅,类似观察者模式。有专门发布事件的组件以及接受通知的监听器组成。
Annotation-based Event Listeners
基于注解的实现事件监听实现。
发布事件的组件需要装配ApplicationEventPublisher对象,使用ApplicationEventPublisher对象发布具体事件:
@Data
@Component
public class EmailService {
private List<String> blackList;
@Autowired
private ApplicationEventPublisher publisher;
public void sendEmail(String address, String content) {
// if (blackList.contains(address)) {
// publisher.publishEvent(new BlackListEvent(this, address, content));
// return;
// }
publisher.publishEvent(new BlackListEvent(this, address, content));
// send email...
}
}
监听方法直接添加注解@EventListener,事件可以作为参数传入,也可以是无参数的方法:
@Component
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...
System.out.println("got BlackListEvent " + event.toString());
}
}
事件定义,普通对象就可以作为事件对象:
public class BlackListEvent {
private EmailService emailService;
private String address;
private String content;
public BlackListEvent(EmailService emailService, String address, String content) {
this.emailService = emailService;
this.address = address;
this.content = content;
}
}
执行如下代码:
EmailService emailService = context.getBean("emailService", EmailService.class);
emailService.sendEmail("xi'an", "content");
执行结果,正常监听到事件:
got BlackListEvent examples.BlackListEvent@52e677af
@EventListener可以用来限制监听的事件种类:
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
@EventListener支持SpEL表达式:
@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlackListEvent(BlackListEvent blEvent) {
// notify appropriate parties via notificationAddress...
}
@EventListener支持返回值为通知事件,handleBlackListEvent函数返回后,会通知相关监听器处理ListUpdateEvent事件,这样可以构造类似锁链式的连续通知:
@EventListener
public ListUpdateEvent handleBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress and
// then publish a ListUpdateEvent...
}
上面的链式通知很明显不能在异步通知中使用:
This feature is not supported for asynchronous listeners.
可以通过返回集合类型发布多个通知:
If you need to publish several events, you can return a Collection of events instead.
Asynchronous Listeners
异步监听器,使用@Async即可实现:
@EventListener
@Async
public void processBlackListEvent(BlackListEvent event) {
// BlackListEvent is processed in a separate thread
}
使用异步通知需要注意两点:
- If the event listener throws an
Exception
, it is not propagated to the caller SeeAsyncUncaughtExceptionHandler
for more details. - Such event listener cannot send replies. If you need to send another event as the result of the processing, inject
ApplicationEventPublisher
to send the event manually.
Ordering Listeners
监听器可以指定监听顺序,通过Order指定:
@EventListener
@Order(42)
public void processBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
Generic Events
因为Spring支持任意Object的子类作为事件类型,所以该节没有意义,直接略过。
1.15.3. Convenient Access to Low-level Resources
1.15.4. Convenient ApplicationContext Instantiation for Web Applications
1.15.5. Deploying a Spring ApplicationContext as a Java EE RAR File
1.15.3 - 1.15.5中没有具体技术相关讲解,建议看官方文档。