`
javachikuang
  • 浏览: 72090 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

ClassPathXmlApplicationContext和FileSystemXmlApplic

阅读更多
分析ApplicationContext
       Spring的bean包支持通过编码方式管理和操作bean的基本功能,ApplicationContext则以Framework的方式提供BeanFactory的所有功能。使用ApplicationContext,你可以让系统加载你的bean(例如,在Servlet容器初始化ContextLoaderServlet时,通过ContextLoader类加载Spring Framework),而不是使用编码方式来加载。
       ApplicationContext接口是context包的基础,位于org.springframework.context包里,提供了BeanFactory的所有功能。除此之外, ApplicationContext为了支持Framework的工作方式,提供了以下的功能:
       l.MessageSource,提供了语言信息的国际化支持
      2.提供资源(如URL和文件系统)的访问支持
      3.为实现了ApplicationListener接口的bean提供了事件传播支持
      4.为不同的应用环境提供不同的context,例如支持web应用的XmlWebApplicationContext类

      下面的源代码分析主要集中在ApplicationContext接口特有的功能上,如国际化支持,资源访问和bean的事件传播。

我的问题
       现在我的问题是,ApplicationContext是如何实现上面提到的功能的?下面的分析将作出回答。

准备测试用例
       1. 首先在类路径根目录编写测试国际化支持的testmsg.xml,并将它加入Spring IDE的管理范围:
       <beans>
            <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
                 <property name="basenames">
                      <list>
                            <value>message</value>
                      </list>
                 </property>
            </bean>
       </beans>

       2. 编写测试用例,测试国际化支持和资源访问的功能。
           public class MsgTest extends TestCase {
                 ApplicationContext ctx = null;
                 public MsgTest(String arg0) {
                       super(arg0);
                 }
                 protected void setUp() throws Exception {
                       super.setUp();
                       ctx = new FileSystemXmlApplicationContext("testmsg.xml");
                 }
                 public void testMessageResource() {
                       Object[] args = {"我", "你"};
                       String msg = ctx.getMessage("hello", args, Locale.CHINA);
                       //System.out.println("msg=" + msg);
                       assertEquals("我和你", msg);
                       Resource rs = ctx.getResource("classpath:log4j.properties");
                       assertTrue(rs.exists());
                }
           }

       3. 在类路径根目录创建属性文件message.properties,内容为hello={0}和{1}。
 
       此时运行TestCase,果然不出所料,Junit视图的测试状态是红条。将打印msg变量的语句打开,重新测试,发现"和"字是乱码。
       在message.properties文件中将"和"字改为ASCII码\u548c,重新运行TestCase,绿条,测试通过。
       将testmsg.xml中bean的id改为messageSource1,重新运行测试,出现红条,测试失败,说明bean的名称必须是messageSource,这点值得注意。至于其中的原因稍后说明。

ApplicationContext类图
       ApplicationContext接口相关的类图如下,其中getParent和publishEvent方法分别支持分层的context和事件传播功能。
 

 
      
       如以上的类继承层次图所示,ApplicationContext接口通过继承BeanFactory,MessageSource和ResourceLoader三个接口,分别支持管理和操作bean的功能,语言信息的国际化支持以及对资源访问的支持。
       AbstractApplicationContect是ApplicationContext的抽象实现类,它的继承层次较为紊乱,我觉得这里应该进行代码重构。AbstractXmlApplicationContext是AbstractApplicationContext的子类,提供了对XML配置文件的支持,它有三个子类,分别用于不同的应用环境。
       对于MessageSource,Spring提供了两个bean实现,ResourceBundleMessageSource和ReloadableResourceBundleMessageSource。前者提供了访问Properties文件的支持,后者添加了无需重启JVM,重新加载Properties文件的支持。

ApplicationContext的国际化和资源访问支持
       1. 如类层次图所示,在我们的例子中,FileSystemXmlApplicationContext使用DefaultListableBeanFactory装载和解释testmsg.xml配置文件(参见代码分析的BeanFactory部分)。

       2. FileSystemXmlApplicationContext根据配置文件的BeanDefinition创建ResourceBundleMessageSource,加载<list>元素定义的Properties文件,并保存在AbstractApplicationContext的属性中。当客户程序调用getMessage方法时,AbstractApplicationContext调用ResourceBundleMessageSource的getMessage方法返回Message信息。

       3. 至于上节提到的MessageSource的id只能是messageSource,是因为AbstractApplicationContext的initMessageSource()方法中,有这样一段代码:
                   this.messageSource = (MessageSource)
                   getBean(MESSAGE_SOURCE_BEAN_NAME);
           其中MESSAGE_SOURCE_BEAN_NAME的定义为:
                   static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
           原因找到了,其实只要稍做代码重构,即可消除这个缺陷。

       4. 如类层次图所示,AbstractApplicationContext继承了DefaultResourceLoader,当客户程序调用getResource方法时,使用父类中实现的方法来处理。
 
ApplicationContext的事件传播

准备测试用例
       1. 首先编写测试用例。
           public class SenderBeanTest extends TestCase {
                ApplicationContext ctx = null;
                protected void setUp() throws Exception {
                    super.setUp();
                    ctx = new FileSystemXmlApplicationContext("testlistener.xml");
                }
                public void testSendEmail() {
                    SenderBean sender = (SenderBean)ctx.getBean("sender");
                    String msg = sender.sendMessage("test message");
                    assertEquals("test message", msg);
                }
           }
       2. 接着编写testlistener.xml配置文件。
           <beans>
               <bean id="sender" class="unittest.SenderBean"/>
               <bean id="listener" class="unittest.MessageListener"/>
           </beans>
       3. 最后编写SenderBean,MessageListener和MessageEvent类。
           public class SenderBean implements ApplicationContextAware {
                  private ApplicationContext applicationContext;
                  public void setApplicationContext(ApplicationContext applicationContext)
                            throws BeansException {
                        this.applicationContext = applicationContext;
                  }
                  public String sendMessage(String msg) {
                        MessageEvent event = new MessageEvent(msg);
                        this.applicationContext.publishEvent(event);
                        return msg;
                  }
            }
 
            public class MessageListener implements ApplicationListener {
                  public void onApplicationEvent(ApplicationEvent event) {
                        if (event instanceof MessageEvent) {
                              System.out.println("I got the message:" + event.getSource());
                        }
                  }
            }
 
            public class MessageEvent extends ApplicationEvent {
                  public MessageEvent(Object source) {
                        super(source);
                        System.out.println(this.getTimestamp() + ":" + source);
                  }
            }
           运行测试案例SenderBeanTest,绿条,测试通过。Console窗口出现以下DEBUG信息:
           ……
           796 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'sender'
           1085553911796:test message
           796 DEBUG support.FileSystemXmlApplicationContext - Publishing event in context [org.springframework.context.support.FileSystemXmlApplicationContext;hashCode=13549765]: unittest.MessageEvent[source=test message]
           I got the message:test message

ApplicationContext有关事件的类图
        ApplicationContext事件传播的类结构图如下。
 
 
事件传播的实现
       1. FileSystemXmlApplicationContext的构造器调用AbstractApplicationContext的refresh方法。如图所示,refresh方法调用refreshListeners方法。
       2. AbstractApplicationContext的refreshListeners方法使用BeanFactory的getBeanOfType方法得到所有ApplicationListener类(本例中是MessageListener),并使用addListener方法把它们都放入ApplicationEventMulticasterImpl的Set容器中(eventListeners变量)。
       3. 如图所示,SenderBean实现ApplicationContextAware接口,并通过setApplicationContext方法注入ApplicationContext对象实例。
       4. 当调用SenderBean类sendMessage方法时,AbstractApplicationContext调用publishEvent方法。
       5. AbstractApplicationContext类的publishEvent方法调用ApplicationEventMulticasterImpl类的onApplicationEvent方法。
       6. ApplicationEventMulticasterImpl通知Set容器中所有的ApplicationListener对象,调用它们的onApplicationEvent方法。
 
       从以上的过程可以看出,ApplicationContext将事件通知所有的ApplicationListener。如果ApplicationListener的子类(如MessageListener)只想接受指定的事件类型,需要自己编写过滤代码,如例子中的if (event instanceof MessageEvent)。
分享到:
评论
1 楼 lifeiniao526 2011-02-24  
高手,真强啊。向你学习一下啊。 

相关推荐

    模拟spring中的ClassPathXmlApplicationContext类的实现

    在Spring中,`ClassPathXmlApplicationContext`是用于加载和管理配置元数据的一个重要类,它允许我们通过XML配置文件来创建和初始化bean。这个类在启动Spring应用上下文时起着关键作用。 `...

    spring的基础(一)自己写的ClassPathXmlApplicationContext类

    `ClassPathXmlApplicationContext`是Spring框架中用于加载和管理配置元数据的核心类,它允许我们通过XML文件来定义和初始化Bean。在Java应用中,Spring作为一个依赖注入(DI)和面向切面编程(AOP)的框架,极大地...

    spring容器的触发事件 ClassPathXmlApplicationContext的start()方法的用法

    通过使用 `ClassPathXmlApplicationContext` 类和事件监听器,开发者可以轻松地扩展应用的功能,同时也能更好地理解和控制 Spring 应用程序的生命周期。 总之,在实际开发过程中,熟练掌握这些事件的触发时机以及...

    spring为ApplicationContext提供的3种实现分别为:ClassPathXmlApplicationContext

    ClassPathXmlApplicationContext和FileSystemXmlApplicationContext适用于传统的XML配置方式,适合于大型项目,因为XML配置可以提供清晰的结构和分离的配置。而AnnotationConfigApplicationContext则更简洁,减少了...

    maven相关资料

    二、ClassPathXmlApplicationContext[只能读放在web-info/classes目录下的配置文件]和FileSystemXmlApplicationContext的区别 classpath:前缀是不需要的,默认就是指项目的classpath路径下面; 如果要使用绝对路径,...

    BoneCP的xml使用实例

    BoneCP是一种高效的、开源的Java连接池实现,它旨在提供比其他常见的数据库连接池如C3P0和DBCP更高的性能。在这个实例中,我们将学习如何通过XML配置文件来使用BoneCP,以及如何在Java代码中加载这个配置。 首先,...

    dubbo的使用

    其设计目标是使服务提供者和服务消费者之间的通信变得简单、高效。在Java分布式开发中,Dubbo扮演着核心角色,类似于Spring框架在单体应用中的作用。 首先,为了使用Dubbo,我们需要配置Zookeeper作为服务注册中心...

    testSpring

    信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@c1f10e: display name [org.springframework.context.support.ClassPathXmlApplicationContext@c1f10e]; startup date [Wed ...

    Spring必背.docx

    ApplicationContext还有三个常用的实现类,分别是FileSystemXmlApplicationContext、ClassPathXmlApplicationContext和WebXmlApplicationContext,其中ClassPathXmlApplicationContext是最常用的。 面向切面编程...

    spring技术详解

    Spring容器有多种实现类,常用的有XmlBeanFactory、FileSystemXmlApplicationContext和ClassPathXmlApplicationContext等。其中,ApplicationContext是BeanFactory的子接口,通常使用...

    Spring完美教程

    Spring框架是Java开发中最常用的企业级应用框架之一,它提供了一种轻量级的容器管理方式,使得开发者可以更轻松地进行依赖注入(Dependency Injection, DI)和面向切面编程(Aspect Oriented Programming, AOP)。...

    Spring获取ApplicationContext对象工具类的实现方法

    Spring框架作为Java EE开发中非常流行和强大的框架之一,为Java应用提供了全面的基础设施支持。在Spring中,ApplicationContext(应用程序上下文)是容器的核心,负责配置和管理应用中对象的生命周期和依赖关系。在...

    ApplicationContext及它的3种实现.docx

    `ApplicationContext`是Spring框架中的核心接口,它是`BeanFactory`接口的一个子接口,提供了更为丰富的功能,主要用于管理和控制Spring应用中的Bean。`ApplicationContext`不仅具备`BeanFactory`的所有功能,还扩展...

    spring读取配置文件

    本篇文章将深入探讨如何在Spring中读取不同目录下的配置文件,以及使用`ClassPathXmlApplicationContext`和`FileSystemXmlApplicationContext`这两种不同的上下文环境来加载它们。 首先,让我们了解`...

    spring3表述了spring的应用

    本文将深入探讨Spring3.0的核心特性,主要包括控制反转(IOC)和依赖注入(DI),以及如何配置和实例化Spring容器。 **1. 控制反转(IOC)与依赖注入(DI)** **控制反转(Inversion of Control, IOC)** 是Spring...

    XFire与Spring集成WebService客户端的两种开发方式.pdf

    1. 引入Spring的相关库,如`ApplicationContext`和`ClassPathXmlApplicationContext`,以便于加载配置和获取bean。 2. 在`client.xml`中配置XFire的客户端bean,指定WSDL的URL和期望的接口类型。 3. 使用`...

    spring完美教程

    Spring框架是Java应用程序开发中的一个核心组件,它提供了一个丰富的依赖注入(DI)容器和面向切面编程(AOP)支持。本教程将深入讲解Spring的核心概念和使用方法,特别适合初学者。以下是对Spring框架及其核心组件...

Global site tag (gtag.js) - Google Analytics