共计 4455 个字符,预计需要花费 12 分钟才能阅读完成。
先看一下 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