先看一下ApplicationContext的类构造:
可知:ApplicationContext是BeanFactory,所以具备BeanFactory的能力:初始化Spring容器(细节下一篇文章剖析),除此之外,ApplicaitonContext还具备如下能力:
- MessageSource接口提供的i18n能力。
- ResourceLoader接口提供的资源文件拜访能力。
- ApplicationListener接口提供的事件公布及监听能力。
- HierarchicalBeanFactory提供的能力。
明天次要关注前3项。
i18n能力
即便不是国际化我的项目,i18n也很实用,比方我的项目中的提示信息或错误信息的治理,切实是见过太多我的项目对错误信息的放任不管,其实提示信息或者错误信息是零碎与用户交互的重要组成部分,有必要认真对待:i18n就是一个抉择。
ApplicationContext通过MessageSource接口提供了i18n能力,简略易用。
Spring提供了MessageSource的3个实现:ResourceBundleMessageSource, ReloadableResourceBundleMessageSource和 StaticMessageSource。咱们就以ResourceBundleMessageSource举例。
咱们晓得应用i18n须要以下步骤:
- 创立property文件,定义message
- 创立MessageSource加载propperty文件
- 通过MessageSource获取property文件定义的message
上面咱们以xml和注解两种形式举例。
1. 创立property文件
创立property文件是通用的,两种形式无区别,所以咱们首先创立property文件。
为了反对中文,咱们须要把我的项目的文件编码方式设置为UTF-8、property文件的编码方式抉择为UTF-8,并且肯定勾选native-to-accii这一选项,否则会呈现中文乱码:
而后在resources目录下创立一个myMessage的、蕴含en和zh两个语言resource Bundle文件,创立实现后如下图:
关上myMessage_en.propperties文件,输出:
msg=this is {0}
关上myMessage_zh.properties文件输出:
msg=我其实就是要汉语的提示信息 {0}
这个时候到classpath下看一下myMessage_zh.properties:
msg=\u7EC8\u4E8E\u53EF\u4EE5\u6C49\u5B57\u4E86\u554A {0}
能够看到是转换为accii码当前的文件了,这个就是native-to-ascii选项的作用,如果这里看到的仍然是汉字,最终进去的大概率是乱码。
好了,properties文件创建好了。
xml形式实现i18n
还是用咱们以前的例子,在mySpring.xml文件中退出如下配置信息,把ResourceBundleMessageSource类加载到Spring容器中并指定配置文件名称为myMessage:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>myMessage</value> </list> </property> </bean>
而后在xml启动类中退出对message的调用代码:
public class AppByXML { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("mySpring.xml"); String msg = applicationContext.getMessage("msg",new Object[]{"汉字"},"default msg", Locale.CHINESE); System.out.println("msg:"+msg); }}
执行启动类:
msg:我其实就是要汉语的提示信息 汉字
而后批改一下启动类,让他调用en配置文件:
public class AppByXML { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("mySpring.xml"); String msg = applicationContext.getMessage("msg",new Object[]{"english"},"default msg", Locale.ENGLISH); System.out.println("msg:"+msg); }
执行启动类:
msg:this is english
xml配置形式下调用applicationContext的i18n性能胜利!
注解形式
只有把MessageSource注入到Spring容器中就能够,所以,在MyConfiguration文件中:
@Configuration()@ComponentScan(value={"springTest"})public class MyConfiguration { @Bean public MessageSource messageSource(){ ResourceBundleMessageSource rbm = new ResourceBundleMessageSource(); rbm.setBasenames("myMessage"); return rbm; }}
启动类:
public class App { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfiguration.class);// (ResourceBundleMessageSource)applicationContext String msg = applicationContext.getMessage("msg",new Object[]{"test"},"default msg", Locale.ENGLISH); System.out.println("msg:"+msg);}
执行启动类就OK。
事件监听
Spring的事件监听机制遵循订阅者模式,整个事件监听框架由以下3局部组成:
- 事件:ApplicationEvent接口实现
- 事件公布:由ApplicationEventPublisher接口实现。
- 事件监听:ApplicationListener接口负责。
因为ApplicationContext实现了ApplicationEventPublisher接口,所以他天生就是事件公布器。
Spring4.2之后,增强了对事件监听机制的反对,能够反对通过注解公布和监听事件,而且不仅反对公布ApplicationEvent事件,还能够反对一般对象(不须要实现ApplicationEvent接口)的事件公布。
公布未实现ApplicationEvent事件后,ApplicationContext会主动封装其为PayloadApplicationEvent:
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType(); } }
原始对象被封装在PayloadApplicationEvent的payload属性中,在监听器中能够通过payload获取。
容许的状况下,还是倡议公布ApplicationEvent事件,这样的话能够实现有针对性的监听器、专门监听相应事件,这种状况下监听器的onApplicationEvent办法中的事件就是类型平安的、不须要检查和强制向下转换。
监听器必须要作为bean注入到Spring容器中,否则的话是监听不到ApplicationContext公布的事件的。
Spring的监听器能够有以下两种实现形式:
- 实现ApplicationListener接口
- 监听办法上应用@EventListener注解
应用层公布事件是须要ApplicationContext对象的,所以,在应用层须要获取到ApplicationContext对象,以什么样的形式获取比拟不便呢?
自然而然,回忆以下后面学习过的内容Spring FrameWork从入门到NB - 定制Bean,其中提到ApplicationContextAware接口:“ApplicationContextAware接口提供了一个机会,让你从一般的Spring Bean中能够取得到创立他的ApplicationContext。”这就够了!
异步监听器
须要特地留神的是,默认状况下,事件监听器的解决逻辑和事件公布的主逻辑是处于同一个线程中同步执行的。益处是事件监听逻辑能够和事件公布逻辑共享事务(如果存在事务、而且业务有要求的话)。
但如果咱们有非凡需要,想要异步事件监听器,该怎么实现呢?
Spring那么NB,实现形式当然非常简单:在Listner上加@Async注解就能够。留神须要在配置类上减少@EnableAsync注解,否则@Async不会失效。
监听事件排序
仍然是要在监听器上做文章,在监听器ApplicationListener上、或者@EnentLister注解办法上应用@Order注解。
上一篇 Spring FrameWork从入门到NB - Environment Abstraction