Spring ApplicationContext

BeanFactory提供了针对Java Bean的管理功能,而ApplicationContext提供了一个更为框架化的
实现(从上面的示例中可以看出,BeanFactory的使用方式更加类似一个API,而非Framework style)。

ApplicationContext覆盖了BeanFactory的所有功能,并提供了更多的特性。此外,
ApplicationContext为与现有应用框架相整合,提供了更为开放式的实现(如对于Web应用,我们可以在
web.xml中对ApplicationContext进行配置)。

相对BeanFactory而言,ApplicationContext提供了以下扩展功能:
1. 国际化支持
我们可以在Beans.xml文件中,对程序中的语言信息(如提示信息)进行定义,将程序中的提示
信息抽取到配置文件中加以定义,为我们进行应用的各语言版本转换提供了极大的灵活性。
2. 资源访问
支持对文件和URL的访问。
3. 事件传播
事件传播特性为系统中状态改变时的检测提供了良好支持。
4. 多实例加载
可以在同一个应用中加载多个Context实例。

 

 

1) 国际化支持
国际化支持在实际开发中可能是最常用的特性。对于一个需要支持不同语言环境的应用而言,
我们所采取的最常用的策略一般是通过一个独立的资源文件(如一个properties文件)完成所
有语言信息(如界面上的提示信息)的配置,Spring对这种传统的方式进行了封装,并提供了
更加强大的功能,如信息的自动装配以及热部署功能(配置文件修改后自动读取,而无需重新
启动应用程序),下面是一个典型的示例:
<beans>
<description>Spring Quick Start</description>
<bean id="messageSource"
class="org.springframework.context.support.ResourceB
undleMessageSource">
<property name="basenames">
<list>
<value>messages</value>
</list>
</property>
</bean>
</beans>
这里声明了一个名为messageSource的Bean(注意对于Message定义,Bean ID必须为
messageSource,这是目前Spring的编码规约),
对应类为ResourceBundleMessageSource
目前Spring中提供了两个MessageSource接口的实现,即
ResourceBundleMessageSourceReloadableResourceBundleMessageSource,后
者提供了无需重启即可重新加载配置信息的特性。
在配置节点中,我们指定了一个配置名“messages”。Spring会自动在CLASSPATH根路

 

径中按照如下顺序搜寻配置文件并进行加载(以Locale为zh_CN为例):
messages_zh_CN.properties
messages_zh.properties
messages.properties
messages_zh_CN.class
messages_zh.class
messages.class
(Spring实际上调用了JDK的ResourceBundle读取配置文件,相关内容请参见JDK文档)
示例中包含了两个配置文件,内容如下:
messages_zh_CN.properties:
userinfo=当前登录用户: [{0}] 登录时间:[{1}]
messages_en_US.properties:
userinfo=Current Login user: [{0}] Login time:[{1}]
我们可以通过下面的语句进行测试:
ApplicationContext ctx=new
FileSystemXmlApplicationContext("bean.xml");
Object[] arg = new Object[]{
"Erica",
Calendar.getInstance().getTime()
};
//以系统默认Locale加载信息(对于中文WinXP而言,默认为zh_CN)
String msg = ctx.getMessage("userinfo", arg);
System.out.println("Message is ===> "+msg);
代码中,我们将一个Object数组arg作为参数传递给ApplicationContext.getMessage方法,这个
参数中包含了出现在最终文字信息中的可变内容,ApplicationContext将根据参数中的Locale信息对其进
行处理(如针对不同Locale设定日期输出格式),并用其替换配置文件中的{n}标识(n代表参数数组中的
索引,从1开始)。
运行上面的代码,得到以下输出的内容:
Message is ===> ¦Ì¡À?¡ã¦Ì???¨®??¡ì: [Erica] ¦Ì???¨º¡À??:[04-7-17 上
午3:27]
乱码?回忆在传统方式下,针对ResourceBundle的编码过程中发生的问题。这是由于转码过程中产
生的编码问题引发的。比较简单的解决办法是通过JDK提供的转码工具native2ascii.exe进行转换。
执行:
native2ascii messages_zh_CN.properties msg.txt
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
再用msg.txt文件替换Messages_zh_CN.properties文件。我们可以看到现在的
Messages_zh_CN.properties变成了如下形式:
userinfo=/u5f53/u524d/u767b/u5f55/u7528/u6237: [{0}]
/u767b/u5f55/u65f6/u95f4:[{1}]
(通过在native2ascii命令后追加-reverse参数,可以将文件转回本地格式)
再次运行示例代码,得到正确输出:
Message is ===> 当前登录用户: [Erica] 登录时间:[04-7-17 上午3:34]
可见,根据当前默认Locale“zh_CN”,getMessage方法自动加载了messages_zh_CN.properties
文件。
每次必须运行native2ascii方法比较繁琐,实际开发中,我们可以通过Apache Ant的Native2Ascii
任务进行批量转码。如:
<native2ascii encoding="GBK" src="${src}" dest="${build}"/>
尝试在代码中指定不同的Locale参数:
String msg = ctx.getMessage("userinfo", arg, Locale.US);
再次运行,可以看到:
Message is ===> Current Login user: [Erica] Login time::[7/17/04 3:35
AM]
这里,getMessage方法根据指定编码“en_US”加载了messages_en_US.properties文件。同
时请注意登录时间部分的变化(Locale不同,时间的输出格式也随之改变)。
getMessage方法还有一个无需Locale参数的版本,JVM会根据当前系统的Locale设定进行相应处
理。可以通过在JVM启动参数中追加“-Duser.language=en”来设定当前JVM语言类型,通过JVM级的
设定,结合国际化支持功能,我们可以较为简单的实现多国语言系统的自动部署切换。
2) 资源访问
ApplicationContext.getResource方法提供了对资源文件访问支持,如:
Resource rs = ctx.getResource("classpath:config.properties");
File file = rs.getFile();
上例从CLASSPATH根路径中查找config.properties文件并获取其文件句柄。
getResource方法的参数为一个资源访问地址,如:
file:C:/config.properties
/config.properties
classpath:config.properties
注意getResource返回的Resource并不一定实际存在,可以通过Resource.exists()方法对
其进行判断。
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
3) 事件传播
ApplicationContext基于Observer模式(java.util包中有对应实现),提供了针对Bean的事件传
播功能。通过Application. publishEvent方法,我们可以将事件通知系统内所有的
ApplicationListener。
事件传播的一个典型应用是,当Bean中的操作发生异常(如数据库连接失败),则通过事件传播
机制通知异常监听器进行处理。在笔者的一个项目中,就曾经借助事件机制,较好的实现了当系统
异常时在监视终端上报警,同时发送报警SMS至管理员手机的功能。
在目前版本的Spring中,事件传播部分的设计还有待改进。同时,如果能进一步支持异步事件处理
机制,无疑会更具吸引力。
下面是一个简单的示例,当LoginAction执行的时候,激发一个自定义消息“ActionEvent”,此
ActionEvent将由ActionListener捕获,并将事件内容打印到控制台。
LoginActoin.java:
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;
}
}
ActionEvent.java:
public class ActionEvent extends ApplicationEvent {
public ActionEvent(Object source) {
super(source);
}
}
ActionListener.java:
public class ActionListener implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
if (event instanceof ActionEvent) {
System.out.println(event.toString());
}
}
}
配置非常简单:
<bean id="loginaction" class="net.xiaxin.beans.LoginAction"/>
<bean id="listener" class="net.xiaxin.beans.ActionListener"/>
运行测试代码:
ApplicationContext ctx=new
FileSystemXmlApplicationContext("bean.xml");
LoginAction action = (LoginAction)ctx.getBean("action");
action.login("Erica","mypass");
可以看到控制台输出:
net.xiaxin.beans.LoginEvent[source=Erica]
org.springframework.context.event.ApplicationEventMulticasterImpl实现了事件传播机
制,目前还相对简陋。
在运行期,ApplicationContext会自动在当前的所有Bean中寻找ApplicationListener接
口的实现,并将其作为事件接收对象。当Application. publishEvent方法调用时,所有的
ApplicationListener接口实现都会被激发,每个ApplicationListener可根据事
件的类型判断是否是自己需要处理的事件,如上面的ActionListener只处理
ActionEvent事件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值