Spring容器(四)

来源:互联网 发布:php curl 获取图片 编辑:程序博客网 时间:2024/05/16 19:34


Spring有两个核心接口:BeanFactory和ApplicationContext。其中ApplicationContext是BeanFactory的子接口。它们可以代表Spring容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean。在基于Spring的JavaEE应用中,所有组件都被当成Bean处理,包括数据源、Hibernate的SessionFactory、事务管理器等。Spring容器还负责管理Bean与Bean之间的依赖关系。

BeanFactory

BeanFactory是Spring最基本的接口,它负责配置、创建、管理Bean,它有一个子接口ApplicationContext,也被称为上下文。BeanFactory接口包含如下几个基本方法:

这里写图片描述

调用者只需使用getBean()方法即可获得指定Bean的引用,无须关心Bean的实例化过程。Bean实例的创建、初始化以及依赖关系的注入都由Spring容器完成。

BeanFactory常用实现类是DefaultListableBeanFactory,ApplicationContext是BeanFactory的子接口,大部分JavaEE应用,使用ApplicationContext作为Spring容器,其常用实现类是FileSystemXmlApplicationContext、ClassPathXmlApplicationContext和AnnotationConfigApplicationContext。如果在Web应用中使用Spring容器,则通常有XmlWebApplicationContext、AnnotationConfigWebApplicationContext两个实现类。

这里写图片描述

创建Spring实例时,必须提供Spring容器管理的Bean的详细配置信息。Spring的配置信息通常采用XML配置文件来配置,因此创建BeanFactory时,用该提供XML配置文件作为参数。XML配置文件通常使用Resource对象传入。

Resource接口是Spring提供的资源访问接口,通过使用该接口,Spring能访问磁盘、类路径和网络上的资源。

大部分JavaEE应用,可以在启动Web应用时自动加载ApplicationContext实例,接受Spring管理的Bean无须知道ApplicationContext的存在,一样可以利用ApplicationContext的管理。

ApplicationContext

大部分时候,不使用BeanFactory实例作为Spring容器,而是使用ApplicationContext实例作为容器,所以也把Spring容器称为上下文。ApplicationContext是BeanFactory接口的子接口,它增强了BeanFactory的功能。

ApplicationContext允许以声明式方式操作容器,无须手动创建它。可利用如ContextLoader的支持类,在Web应用启动时自动创建ApplicationContext。也可采用编程方式创建ApplicationContext。除了拥有BeanFactory所支持的所有功能以外,ApplicationContext还有如下额外功能:

- ApplicationContext默认会初始化所有的Singleton Bean,可通过配置取消初始化。
- ApplicationContext继承MessageSource接口,因此提供国际化支持。
- 同时加载多个配置文件。
- 以声明方式启动并创建Spring容器。

ApplicationContext包括BeanFactory所有功能,一般建议使用ApplicationContext,除非对于某些内存非常关键的应用,才考虑使用BeanFactory。

当系统创建ApplicationContext容器时,默认会预初始化所有的Singleton Bean。即当ApplicationContext容器初始化完成后,容器会自动初始化所有的singleton Bean,包括调用构造器创建该Bean的实例,并根据< property…/>元素执行setter方法。这意味着系统前期创建ApplicationContext时将有较大的系统开销,但一旦ApplicationContext初始化完成,程序后面获取Singleton Bean时将拥有较好的性能。

<bean id="Chinese" class="com.afy.spring.beans.Person">    <property name="test" value="猪八戒"></property></bean>

这里配置了一个Chinese Bean,没有特别设置的话,该Bean就是Singleton Bean,ApplicationContext会在容器初始化完成后,自动调用Person类的构造器创建Chinese Bean,并以“猪八戒”作为传入参数去调用Chinese Bean的setTest()方法。
程序中的Person类代码如下:

public class Person{   public Person(){      System.out.println("==正在执行Person无参构造器==");   }   public void setTest(String name){      System.out.println("正在调用setName()方法,传入参数:"+name);   }}


即使主程序只有一行代码:

//创建Spring容器ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

上面代码只是使用ApplicationContext创建了Spring容器,ApplicationContext会自动预初始化容器中的Chinese Bean——包括调用它的无参构造器,根据< property…/>元素执行setter方法,执行上面代码后输出:

==正在执行Person无参构造器==
正在调用setName()方法,传入参数:猪八戒


使用BeanFactory做Spring容器则不会预初始化容器中的Bean,如果要阻止ApplicationContext预初始化容器中的singleton Bean,可以为< bean…/>元素指定lazy-init=”true”。

ApplicationContext通常的实现:

FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供它的构造函数。
ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里需要正确设置classpath因为这个容器将在classpath里找bean配置。
WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。

Bean 工厂和 Application contexts 的区别

Application contexts提供一种方法处理文本消息,一个通常的做法是加载文件资源(比如镜像),它们可以向注册为监听器的bean发布事件。另外,在容器或容器内的对象上执行的那些不得不由bean工厂以程序化方式处理的操作,可以在Application contexts中以声明的方式处理。Application contexts实现了MessageSource接口,该接口的实现以可插拔的方式提供获取本地化消息的方法。

ApplicationContext的国际化支持

ApplicationContext继承了MessageSource接口,因此具有过国际化功能。MessageSource接口中定义的用于国际化的方法有:

这里写图片描述

当程序创建ApplicationContext容器时,Spring自动查找配置文件中名为 messageSource的Bean实例,一旦找到这个Bean实例,上述两个方法的调用就委托给messageSource Bean.如果没有messageSource Bean,ApplicationContext会找其父容器中的messageSource Bean,如果找到将以此为messageSource使用。如果无法找到messageSource Bean,系统会创建一个空的StaticMessageSource Bean,该Bean能接受上述两个方法的调用。

在Spring中配置 messageSource Bean时通常使用ResourceBundleMessageSource类,看下面的配置文件:

这里写图片描述

然后给出两个资源文件:
第一份为美式英语的资源文件,文件名为:message_en_US_.properties

hello=welcome,{0}
now=now is:{0}

第二份为简体中文的资源文件,文件名为:message.properties

hello=欢迎你,{0}
now=现在时间是:{0}


由于包含非西欧文字,所以使用native2ascii工具将这份资源文件国际化,命令为:

native2acsii message.properties message_zh_CN.properties


执行上面命令后,将看到系统会多出一个message_zh_CH.properties文件,该文件为简体中文实际的国际化文件。此时,程序拥有了两份资源文件,可以自适应美式英语和简体中文的环境。主程序部分代码如下:

public class SpringTest{    public static void main(String[] args)throws Exception{        // 实例化ApplicationContext       ApplicationContext ctx = new       ClassPathXmlApplicationContext("beans.xml");        // 使用getMessage()方法获取本地化消息。        // Locale的getDefault方法返回计算机环境的默认Locale       String hello = ctx.getMessage("hello" , new String[]{"孙悟空"}, Locale.getDefault(Locale.Category.FORMAT));       String now = ctx.getMessage("now" , new Object[]{new Date(), Locale.getDefault(Locale.Category.FORMAT));       // 打印出两条本地化消息       System.out.println(hello);       System.out.println(now);    }}


上面程序的执行结果会因环境不同而改变,在简体中文环境下,执行结果如下:

欢迎你,孙悟空
现在时间是14-5-10 下午 3;27

在美国英语环境下,执行结果如下:

welcome:孙悟空
now is :5/10/14 3:27 PM

即使在英文环境下,“孙悟空”这个词也无法变成中文,因为这三个字是写在程序代码中,而不是从资源文件中获得的。

Spring国际化的支持,是建立在Java国际化的基础上的。核心思路是将程序需要国际化的信息写入资源文件,而代码中仅仅使用相应的各信息的Key。

ApplicationContext的事件机制

ApplicationContext的事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext的事件处理。如果容器中有一个ApplicationListener Bean,每当ApplicationContext发布了ApplicationEvent时,ApplicationListener Bean将自动被触发。Spring的事件框架有如下两个主要成员:

1. ApplicationEvent:容器事件,必须由ApplicationContext发布。
2. ApplicationListener:监听器,可由容器中的任何监听器Bean担任。

Spring的事件机制和所有的事件机制基本相似,它们都由事件源、事件和事件监听器组成。只有此处的事件源是ApplicationContext,且事件必须由Java程序显式触发。下图给出了Spring容器的事件机制示意图:

这里写图片描述

下面将在程序中示例Spring容器的事件机制。程序先定义一个ApplicationEvent类,其对象就是一个Spring容器事件。ApplicationEvent类的代码如下:

public class EmailEvent extends ApplicationEvent{    private String address;    private String text;    public EmailEvent(Object source){        super(source);    }    // 初始化全部成员变量的构造器    public EmailEvent(Object source , String address , String text){        super(source);        this.address = address;        this.text = text;    }    // address的setter和getter方法    public void setAddress(String address){        this.address = address;    }    public String getAddress(){        return this.address;    }    // text的setter和getter方法    public void setText(String text){        this.text = text;    }    public String getText(){        return this.text;    }}

上面的EmailEvent类继承了ApplicationEvent抽象类,除此之外,它便是一个普通的Java类。当一个普通的Java类继承了ApplicationEvent基类,该对象就可作为Spring容器的容器事件。

容器事件的监听器类必须实现ApplicationListener接口,实现该接口必须实现onApplicationEvent(ApplicationEvent event)方法,每当容器内发生任何事件时此方法都触发。下面是容器监听器类代码:

public class EmailNotifier implements ApplicationListener{    // 该方法会在容器发生事件时自动触发    public void onApplicationEvent(ApplicationEvent evt){        // 只处理EmailEvent,模拟发送email通知...        if (evt instanceof EmailEvent){            EmailEvent emailEvent = (EmailEvent)evt;            System.out.println("需要发送邮件的接收地址  "                + emailEvent.getAddress());            System.out.println("需要发送邮件的邮件正文  "                + emailEvent.getText());        }        else{            // 其他事件不作任何处理            System.out.println("其他事件:" + evt);        }    }}

将监听器配置在容器中:

<bean class="com.afy.ssh.spring.EmailNotifier"/>

为Spring容器注册事件监听器只要进行简单配置,只要在Spring中配置一个实现了ApplicationListener接口的Bean,Spring容器就会把这个Bean当成容器事件的事件监听器。

当系统创建Spring容器、加载Spring容器时会自动触发容器事件,容器事件监听去可以监听到这些事件。此外,程序可以调用ApplicationContext的pulishEvent()方法来主动触发容器事件:

public class SpringTest{    public static void main(String[] args){        ApplicationContext ctx = new            ClassPathXmlApplicationContext("beans.xml");        // 创建一个ApplicationEvent对象        EmailEvent ele = new EmailEvent("test" ,            "spring_test@163.com" , "this is a test");        // 发布容器事件        ctx.publishEvent(ele);    }}

上面代码创建了ApplicationEvent对象,并通过ApplicationContext主动触发了该事件。运行结果:

[java]其他事件……
[java]需要发送邮件的接受地址 spring_test@163.com
[java]需要发送邮件的邮件正文 this is a test

监听器不仅监听到程序触发的事件,也监听到容器内置的事件。如果开发者需要在Spring容器初始化、销毁时回调自定义方法,就可以通过上面的事件监听器来实现。

1 0
原创粉丝点击