context的核心作用是ApplicationContext接口,这是由BeanFactory接口派生而来。同时,context还提供了以下的功能:
1) MessageSource,提供国际化的消息访问
2)资源访问,如URL和文件
3)事件传播,实现了ApplicationListener接口的bean
4)惯入多个上文,使得每一个上下文都专注于一个特定的层次,比如应用的web层.
1.MessageSource
ApplicationContext
接口扩展了MessageSource
接口,因而提供了消息处理的功能(i18n或者国际化)。与HierarchicalMessageSource
一起使用,它还能够处理嵌套的消息,这些是Spring提供的处理消息的基本接口。让我们快速浏览一下它所定义的方法:
-
String getMessage(String code, Object[] args, String default, Locale loc):用来从
MessageSource
获取消息的基本方法。如果在指定的locale中没有找到消息,则使用默认的消息。args中的参数将使用标准类库中的MessageFormat
来作消息中替换值。 -
String getMessage(String code, Object[] args, Locale loc):本质上和上一个方法相同,其区别在:没有指定默认值,如果没找到消息,会抛出一个
NoSuchMessageException
异常。 -
String getMessage(MessageSourceResolvable resolvable, Locale locale)
:上面方法中所使用的属性都封装到一个MessageSourceResolvable
实现中,而本方法可以指定MessageSourceResolvable
实现。
当一个ApplicationContext
被加载时,它会自动在context中查找已定义为MessageSource
类型的bean。此bean的名称须为messageSource
。如果找到,那么所有对上述方法的调用将被委托给该bean。否则ApplicationContext
会在其父类中查找是否含有同名的bean。如果有,就把它作为MessageSource
。如果它最终没有找到任何的消息源,一个空的StaticMessageSource
将会被实例化,使它能够接受上述方法的调用。
Spring目前提供了两个MessageSource
的实现:ResourceBundleMessageSource
和StaticMessageSource
。它们都继承NestingMessageSource
以便能够处理嵌套的消息。StaticMessageSource
很少被使用,但能以编程的方式向消息源添加消息。ResourceBundleMessageSource
会用得更多一些,为此提供了一下示例:
- <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>
这段配置文件告诉我们资源文件加载的方式,它可以从format.properties,exceptions.properties,windows.properties三个文件里分别加载我们需要的资源,且它们是按配置文件夹的顺序加载的。
我们可以分别往三个文件里加
- # in 'format.properties'
- message=Alligators rock format!
- # in 'exceptions.properties'
- argument.required=The {0} argument is required.
... ...
测试代码如下:
- public static void main(String[] args) {
- MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
- String message = resources.getMessage("message", null, "Default", null);
- System.out.println(message);
- }
打印的结果就是:
- Alligators rock format!
对于第二个参数可以用如下方法测试:
- MessageSource resources = new ClassPathXmlApplicationContext("bean.xml");
- String message = resources.getMessage("argument.required",
- new Object [] {"userDao"}, "Required", Locale.UK);
- System.out.println(message);
2.资源访问
如:
- Resource rs = ctx.getResource("classpath:config.properties");
- File file = rs.getFile();
可以直接访问资源文件
3.事件传播
ApplicationContext基于观察者模式提供了对Bean的事件传播功能,通过Application.publicEvent访问方法,可以将事件通知系统内所有的ApplicationListener
事件传播的一个典型应用是,当Bean中的操作发生异常(如数据库连接失败),则通过事件传播
机制通知异常监听器进行处理
ApplicationListener是由在配置文件中配置我们感兴趣的监听,如这里我们配置两个监听ActionListener1和ActionListener1它们的配置文件为:
- <bean id="action" class="org.spring.LoginAction" /> //登录动作
- <bean id="listener1" class="org.spring.ActionListener1" />
- <bean id="listener2" class="org.spring.ActionListener2" />
类为:
- public class ActionListener1 implements ApplicationListener {
- public void onApplicationEvent(ApplicationEvent event) {
- if (event instanceof ActionEvent) {
- System.out.println("ActionListener1:"+event.toString());
- }
- }
- }
- public class ActionListener2 implements ApplicationListener {
- public void onApplicationEvent(ApplicationEvent event) {
- if (event instanceof ActionEvent) {
- System.out.println("ActionListener2:"+event.toString());
- }
- }
- }
定义登录事件ActionEvent:
- public class ActionEvent extends ApplicationEvent {
- public ActionEvent(Object source) {
- super("actionEvent "+source);
- }
- }
而登录动作的具体实现它要实现接口 ApplicationContextAware
- public class LoginAction implements ApplicationContextAware {
- private ApplicationContext applicationContext;
- public void setApplicationContext(ApplicationContext applicationContext)
- throws BeansException {
- this.applicationContext = applicationContext;
- }
- public int login(String username, String password) {
- ActionEvent event = new ActionEvent(username);
- this.applicationContext.publishEvent(event);
- return 0;
- }
- public static void main(String[] args) {
- ApplicationContext ctx=new
- FileSystemXmlApplicationContext("WebRoot/WEB-INF/bean.xml");
- LoginAction action = (LoginAction)ctx.getBean("action");
- action.login("hell","hell");
- }
- }
结果当我们login时,就会通过acclicationContext来通知当前有的监听,使所有监听者知道一下。到于监听者对于这个登录事件是否感兴趣,那是他们自个的事了。。。
4.多个上下文:
以下摘自(夏昕)
上面的示例中,ApplicationContext均通过编码加载。对于Web应用,Spring提供了可配置的
ApplicationContext加载机制。
加载器目前有两种选择:ContextLoaderListener和ContextLoaderServlet。这两者在功能上完全
等同,只是一个是基于Servlet2.3版本中新引入的Listener接口实现,而另一个基于Servlet接口实现。
开发中可根据目标Web容器的实际情况进行选择。
配置非常简单,在web.xml中增加:
- <listener>
- <listener-class>
- org.springframework.web.context.ContextLoaderListener
- </listener-class>
- </listener>
或者
- <servlet>
- <servlet-name>context</servlet-name>
- <servlet-class>
- org.springframework.web.context.ContextLoaderServlet
- </servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
通过以上配置,Web容器会自动加载/WEB-INF/applicationContext.xml初始化
ApplicationContext实例,如果需要指定配置文件位置,可通过context-param加以指定:
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/myApplicationContext.xml</param-value>
- </context-param>
配置完成之后可通过 WebApplicationContextUtils.getWebApplicationContext
方法在Web应用中获取ApplicationContext引用。