ApplicationContext相对于BeanFactory多了国际化和事件发布等新功能,下面就对这些新功能或是说支持做一个总结。
国际化
首先说下国际化信息支持(I18n MessageSource),I18是Internationalization的缩写,因为这个但此很长并且有18个字母。在JavaSE中,我们使用Locale和ResourceBundle类(请自行参考Java SDK)来实现国际化。Spring的一大原则就是不重新发明轮子,所以在JavaSE的基础上抽象出了一个MessageSource接口,这个接口里有只有三个getMessage方法,而参数除了上面提到的Locale外,还可能有信息的键(code)、参数数组(args)、找不到Message时默认信息(defaultMessage)和对资源条目的键以及信息参数等进行封装的MessageSourceResolvable对象。
Spring提供了三种MessageSource的实现:
StaticMessageSource:简单实现,多用于测试,不应该用于开发。
ResourceBundleMessageSource:。基于ResourceBundle实现,提供多个缓存来提高查询速度,对于参数化和非参数化信息的处理进行了优化,并对MessageFormat实例也进行了缓存,最常用的实现。
ReloadableResourceBundleMessageSource:相对于第二种实现,多了一个cacheSeconds属性用来指定时间段,以定期刷新并检查properties文件的变更。
ApplicationContext继承了MessageSource接口,但ApplicationContext会在容器中寻找一个名称为messageSource的MessageSource实现来完成国际化职责。如果找不到,ApplicationContext内部会默认实例化一个不含任何内容的StaticMessageSource实例,以
保证相应的方法调用。由于StaticMessageSource并不适合用于开发环境,所以通常情况下,要使用国际化功能,我们都会在Spring的配置文件中加入如下一个bean:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>messages</value> <value>errorcodes</value> </list> </property> </bean>
这样我们就可以访问相应Locale对应的信息:
ApplicationContext ctx = ...;
String fileMenuName = ctx.getMessage("menu.file", new Object[]{"F"}, Locale.US);
String editMenuName = ctx.getMessage("menu.file", null, Locale.US);
当然MessageSource的实现可以不需要依赖ApplicationContext而单独使用。同样的,Spring也提供了一个MessageSourceAware接口(一般不会使用,会造成容器的侵入性较强)。一般如果某些业务需要使用MessageSource的实现,一般的做法是将ApplicationContext中的messageSource注入到对应的bean中。
容器内部事件发布
首先也是要说一下javaSE中的事件发布,通过扩展指定的类和接口,包括EventObject(自定义事件类)类和EventListener(事件监听器)接口,我们就可以拥有自定义事件与对应的监听器。最后通过一个EventPublisher将事件发布。
ApplicationContext同样继承了ApplicationEventPublisher接口,也就是说,ApplicationContext就是一个事件发布者。在Spring中,事件全部扩展自ApplicationEvent抽象类(继承自EventObject),而监听器全部扩展自ApplicationListener接口(继承自EventListener)。ApplicationContext容器在启动时,会自动识别并加载EventListener类型bean,一旦容器内有事件发布,将通知这些注册到容器的EventListener。
Spring提供了ApplicationEvent的三个实现类:
ContextClosedEvent:容器即将关闭时发布的事件。
ContextRefreshedEvent:容器在初始化或者刷新时发布的事件。
RequestHandledEvent:Web请求处理后发布的事件,其子类ServletRequestHandledEvent提供Java EE的Servlet相关事件。
ApplicationContext的实现类在实现事件发布和事件监听器注册时,会把这些事转包给ApplicationEventMulticaster的接口。该接口定义了具体事件监听器的注册管理以及事件发布的方法。ApplicationEventMulticaster有一抽象实现类AbstractApplicationEventMulticaster,其实现类 SimpleApplicationEventMulticaster包含了事件发布功能的实现。SimpleApplicationEventMulticaster默认使用了SyncTaskExecutor进行事件的发布,这就使事件是同步顺序发布的。为了避免这种方式可能存在的性能问题,我们可以为其提供其他类型的TaskExecutor 实现类。(TaskExecutor以后说明)。
ApplicationContext容器在启动时,会检查容器内是否存在名为applicationEventMulticaster的ApplicationEventMulticaster对象实例,没有则默认初始化一个SimpleApplicationEventMulticaster作为将会使用的ApplicationEventMulticaster。
事件发布的具体代码可以自己实现一下,其实就是事件继承ApplicationEvent,监听器实现ApplicationListener,EventPublisher中有一个ApplicationEventPublisher成员,在配置文件中将监听器和EventPublisher注册到ApplicationContext容器中即可。