Spring-----4、使用Spring容器

Spring有两个核心接口:BeanFactory和ApplicationContext(BeanFactory的子接口);他们都可代表Spring容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean;Bean是Spring管理的基本单位,在基于Spring的JavaEE应用中,所有的组件都被当成Bean处理,包括数据源、Hibernate的SesisonFactoy、事务管理器等

应用中的所有组件,都处于Spring的管理下,都被Spring以Bean的方式管理,Spring负责创建Bean实例,并管理其生命周期

Spring容器负责创建Bean实例,所以需要知道每个Bean的实现类,Java程序面向接口编程,无须关心Bean实例的实现类;但Spring容器必须能精确知道每个Bean实例的实现类,因此Spring配置文件必须精确配置Bean实例的实现类

一、Spring容器

Spring容器最基本的接口就是BeanFactory:负责配置、创建、管理Bean;负责管理Bean与Bean之间的依赖关系;其实现类有XmlBeanFactory;其子类ApplicationContext的实现类有ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、AnnotationConfigApplicationContext;在Web应用中使用Spring容器,通常有XmlWebApplicationContext、AnnotationConfigApplicationContext

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

BeanFactory接口常用方法:

boolean containsBean(String beanId):判断Spring容器是否包含id为beanId的Bean实例

<T> T getBean(Class<T> requiredType):获取Spring容器中属于requiredType类型的、唯一的Bean实例

Obejct getBean(String beanId):返回容器id为beanId的Bean实例

<T> T getBean(String beanId,Class<T> requiredType):返回容器id为beanId,并类型为requiredType的Bean

Class<?> getType(String beanId):返回容器中指定Bean实例的类型

对于独立的应用程序,可通过如下方法实例化BeanFactory:
// 搜索当前文件路径下的beans.xml文件创建Resource对象
InputStreamResource isr = new FileSystemResource(“bean.xml”);
// 以Resource对象作为参数,创建BeanFactory实例
XmlBeanFactory factory = new XmlBeanFactory(isr);
或
// 搜索类加载路径,以类加载路径下的beans.xml文件创建Resource对象
ClassPathResource res = new ClassPathResource(“beans.xml”);
// 以Resource对象为参数,创建BeanFactory实例
XmlBeanFactory factory = new XmlBeanFactory(res);
应用中有多个属性配置文件,应采用BeanFcatory的子接口ApplicationContext来创建BeanFactory的实例
ApplicationContext常用实现类:
FileSystemXmlApplicationContext:以基于文件系统的XML配置文件创建ApplicationContext实例
ClassPathXmlApplicationContext:以类加载路径下的XML配置文件创建ApplicationContext实例
需同时加载多个XML配置文件,可采用如下方式:
// 搜索CLASSPATH路径,以CLASSPATH路径下的bean.xml、service.xml文件创建ApplicationContext
ApplicationContext appContext = new ClassPathXmlApplicationContext(new String[]{“bean.xml”,”service.xml”});
或
// 以指定路径下的bean.xml、service.xml文件创建ApplicationContext
ApplicationContext appContext = new FileSystemXmlApplicationContext(new String[]{“bean.xml”,“service.xml”});
Spring配置文件可用XML Schema来定义配置文件的语义约束;也可用DTD(不能用Spring2.X、Spring3.0所新增的配置标签)
<?xml version="1.0" encoding="UTF-8"?>
<!-- 使用spring-beans-3.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   ………………
</beans>

<?xml version="1.0" encoding="UTF-8"?>
<!-- 指定Spring配置文件的DTD信息 -->
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
   ...
</beans>

二、使用ApplicationContext

Application允许以声明式方式操作容器,无须手动创建它;可利用如ContextLoader的支持类,在Web应用启动时自动创建ApplicaionContext;也可用编程方式创建ApplicationContext

除提供BeanFactory所支持的全部功能外,ApplicationContext还有如下额外功能:

继承MessageSource接口,因此提供国际化支持

资源访问,比如URL和文件

事件机制

载入多个配置文件

以声明式启动、并创建Spring容器

当系统创建ApplicationContext容器时,默认预初始化所有singleton Bean;即当ApplicationContext容器初始化完成后,容器中所有singleton Bean也实例化完成

三、ApplicationContext的国际化支持

MessageSource接口中用于国际化的方法:

String getMessage(Stringcode,Object[] args,Locale loc)

String getMessage(Stringcode,Object[] args,Stringdefault,Locale loc)

String getMessage(MessageSourceResolvableresolvable,Locale locale)

ApplicationContext正是通过这三个方法来完成国际化的,当程序创建ApplicationContext容器时,Spring自动查找在配置文件中名为messageSource的Bean实例,一旦找到这个Bean实例,上述3个方法的调用被委托给该messageSource Bean;若没有该Bean,ApplicationContext会查找其父定义中的messageSourceBean;若找到,它被作为messageSource使用;

若无法找到messageSource Bean,系统将创建一个空的StaticMessageSourceBean,该Bean能接受上述三个方法的调用;

在Spring中配置messageSource Bean时通常使用ResourceBundleMessageSource类

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
          <property name="basenames">
              <list>
                  <value>message</value>
                  <!-- 若有多个资源文件,全部列在此处 -->
              </list>
          </property>
</bean>
美式英语资源文件(message_en_US.properties)
hello=welcome,{0}
now=now is:{0}
简体中文资源文件(message.properties)
hellow=欢迎你,{0}
now=现在时间是:{0}

因为该资源文件包含了非西欧文字,应使用native2ascii工具(JDK中bin目录下有)将这份资源文件国际化:
将该文件放到jdk的bin目录下
然后输入命令native2ascii message.properties message_zh_CN.properties
public class SpringTest {
      public static void main(String[] args) {
           ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
           // 创建数组
           String[] a = { "读者" };
           // 使用getMessage方法获取本地化信息;Locale的getDefault方法
           String hello = ctx.getMessage("hello", a, Locale.getDefault());
           Object[] b = { new Date() };
           String now = ctx.getMessage("now", b, Locale.getDefault());
           // 打印出两条本地化消息
           System.out.println(hello);
           System.out.println(now);
      }
}

四、ApplicationContext的事件机制

ApplicationContext的事物机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可实现ApplicationContext的事物处理;若容器中有一个ApplictionListenerBean,每当ApplicaitonContext发布ApplicationEvent时,ApplicationListener Bean将自动被触发

Spring的事件框架有如下两个重要成员:

ApplicationEvent:容器事件,必须由ApplicationContext发布

ApplicationListener:监听器,可由容器中的任何监听器Bean担任

实际上,Spring的事件机制与所有事件机制都基本相似,它们都需要事件源、事件和事件监听器组成;只是此处的事件源是ApplicationContext,且事件必须由Java程序显示触发

/**
 * 定义一个ApplicationEvent类,其对象就是一个Spring容器事件
 *
 */
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;
      }

      public String getAddress() {
           return address;
      }

      public void setAddress(String address) {
           this.address = address;
      }

      public String getText() {
           return text;
      }

      public void setText(String text) {
           this.text = text;
      }
}
/**
 * 容器监听器类
 */
public class EmailNotifier implements ApplicationListener {

      /**
       * 每当容器内发生任何事件时,此方法都被触发
       */
      @Override
      public void onApplicationEvent(ApplicationEvent evt) {
           if (evt instanceof EmailEvent) {
                 // 只处理EmailEvent,发送email通知。。。
                 EmailEvent emailEvent = (EmailEvent) evt;
                 System.out.println("需要发送邮件的接受地址" + emailEvent.getAddress());
                 System.out.println("需要发送邮件的邮件正文" + emailEvent.getText());
           } else {
                 // 容器内置事件不作任何处理
                 System.out.println("容器本身的事件: " + evt);
           }
      }
}
<beans>
      <!-- 配置监听器 -->
      <bean class="org.app.main.EmailNotifier"/>
</beans>

<!-- 当在Spring中配置一个实现了ApplicationListener的Bean,Spring容器就会把这个Bean当成容器事件的监听器 -->
<!-- 当系统创建Spring容器、加载Spring容器时会自动触发容器事件,容器事件监听器可监听到这些事件 -->
<!-- 此外,程序也可调用ApplicationContect的pulishEvent()方法来主动触发容器事件-->
/**
 * 程序调用ApplicationContext的publishEvent来触发事件
 *
 */
public class SpringTest {

      public static void main(String[] args) {
           ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
           // 创建一个ApplicationEvent对象
           EmailEvent ele = new EmailEvent("hello", "[email protected]", "this is a test");
           // 主动触发容器事件
           ctx.publishEvent(ele);
      }
}

运行结果:

容器本身的事件: org.springframework.context.event.ContextRefreshedEvent[source=org[email protected]2d776d65: startup date [Fri Nov 21 14:48:01 GMT+08:00 2014]; root of context hierarchy]

需要发送邮件的接受地址[email protected]

需要发送邮件的邮件正文this is a test

从执行结果可看出,监听器不仅监听到程序所触发的事件,也监听到容器内置的事件;实际上,若开发者需要在Spring容器初始化、销毁时回调自定义方法,就可通过上面事件监听器来实现

若Bean想发布事件,则Bean必须获得其容器的引用;若程序中没有直接获取容器的引用,则应该让Bean实现ApplicationContextAware或BeanFactoryAware接口,从而可以获得容器的引用

Spring提供的几个内置事件:

ContextRefreshedEvent:ApplicationContext容器初始化或刷新触发该事件;此处的初始化是指所有Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean被预实例化,ApplicationContext容器已就绪可用

ContextStartedEvent:当使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的start()方法启动ApplicationContext容器时触发该事件;容器管理生命周期的Bean实例将获得一个指定的启动信号,这在经常需要停止后重新启动的场合比较常见

ContextClosedEvent:当使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的close()方法关闭ApplicationContext容器时触发该事件

ContextStoppedEvent:当使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的stop()方法停止ApplicationContext容器时触发该事件;此处的“停止”意味着容器管理生命周期的Bean实例将获得一个指定的停止信号,被停止的Spring容器可再次调用start()方法重新启动

RequestHandledEvent:Web相关的事件,只能应用与使用DispatcherServlet的Web应用;在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件

五、让Bean获取Spring容器

前面介绍的几个例子都是程序先创建Spring容器,再调用Spring容器的getBean()方法来获取Spring容器中的Bean;在这种访问模式下,程序总是持有Spring容器的引用

但在实际应用中,尤其是Web应用中,Spring容器通常采用声明式方式配置产生:在web.xml文件中配置一个Listener,该Listener将会负责初始化Spring容器;前端MVC框架可直接调用Spring容器(无须访问Spring容器本身);在这种情况下,容器中Bean处于容器管理下,无须主动访问容器,只需接受容器的注入管理即可;Bean实例的依赖关系通常由容器动态注入,无须Bean实例主动请求

在这种情况下,Spring容器中Bean通常不会需要访问容器中其他的Bean-----采用依赖注入,让Spring把依赖的Bean注入到依赖Bean中即可;但在某些特殊情况下,容器中的Bean可能需要主动访问Spring容器本身,Spring也为这种需求做好了准备

实现BeanFactoryAware接口的Bean,拥有访问BeanFactory容器的能力,实现BeanFactoryAware(/ApplicationContextAware)接口的Bean实例被容器创建后,他会有一个引用,该引用指向创建它的BeanFactory;BeanFactoryAware接口只有setBeanFactory(BeanFactorybeanFactory)(/setApplicationContext(ApplicationContextappicationContext))方法:该方法中的beanFactory指向创建它的BeanFactory;该方法由Spring调用;当Spring容器调用该方法时,它会把自身作为参数传入该方法

/**
 * 定义Bean类,实现ApplicationContextAware接口,该类将拥有访问容器的能力
 *
 */
public class Chinese implements ApplicationContextAware {
      // 将BeanFactory容器以成员变量保存
      private ApplicationContext ctx;

      /**
       * 实现ApplicationContextAware接口必须实现的方法
       */
      @Override
      public void setApplicationContext(ApplicationContext ctx) throws BeansException {
           this.ctx = ctx;
      }

      // 获得ApplicaitonContext的测试方法
      public ApplicationContext getContext() {
           return ctx;
      }
}

实现ApplicationContextAware接口让Bean拥有了访问容器的能力,但污染了代码,导致代码与Spring接口耦合在一起;因此,若不是特别必要,不要直接访问容器

时间: 2024-11-06 16:47:47

Spring-----4、使用Spring容器的相关文章

Spring与SpringMVC的容器关系分析

Spring和SpringMVC作为Bean管理容器和MVC层的默认框架,已被众多WEB应用采用,而实际使用时,由于有了强大的注解功能,很多基于XML的配置方式已经被替代,但是在实际项目中,同时配置Spring和SpringMVC时会出现一些奇怪的异常,比如Bean被多次加载,多次实例化,或者依赖注入时,Bean不能被自动注入,但是明明你已经将该Bean注册了的.找原因还是要看问题的根源,我们从容器说起. 在Spring整体框架的核心概念中,容器是核心思想,就是用来管理Bean的整个生命周期的,

配置Spring的用于初始化容器对象的监听器

<!-- 配置Spring的用于初始化容器对象的监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> &l

Spring和SpringMVC父子容器关系初窥

一.背景 最近由于项目的包扫描出现了问题,在解决问题的过程中,偶然发现了Spring和SpringMVC是有父子容器关系的,而且正是因为这个才往往会出现包扫描的问题,我们在此来分析和理解Spring和SpringMVC的父子容器关系并且给出Spring和SpringMVC配置文件中包扫描的官方推荐方式. 二.概念理解和知识铺垫 在Spring整体框架的核心概念中,容器是核心思想,就是用来管理Bean的整个生命周期的,而在一个项目中,容器不一定只有一个,Spring中可以包括多个容器,而且容器有上

使用Spring.NET的IoC容器

使用Spring.NET的IoC容器 0. 辅助类库 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SpringDemo.Pub { public static class Pub { public static string ServiceNameA = "SpringDemo.Lib.Oracle.OracleDatabase"; pub

Spring技术内幕——Spring Framework的IOC容器实现(一)

一.SpringIOC容器概述 IOC容器和依赖反转的模式 在面向对象的系统中,对象封装了数据和对数据的处理,对象的依赖关系常常体现在对数据和方法的依赖上.这些依赖关系可以通过把对象的依赖注入交给框架IOC容器来完成.他可以再解耦代码的同时提高了代码的可测试性. 依赖控制反转的实现由很多种方式,在Spring中,IOC容器是实现这个模式的载体,他可以再对象生成或者初始化时直接将数据注入到对象中,也可以通过将对象引用注入到对象数据域中的方式来注入对方法调用的依赖.这种依赖注入是可以递归的,对象被逐

Spring系列之核心容器

[回顾] 在上篇博客中,我们清楚了Spring的核心IOC,博客的结尾,提出了关于容器的问题.在Spring框架中,容器扮演者重要的角色.容器是什么?Java容器?Spring容器?这几个词,大家都很熟悉,但真正知道么?本篇博客的重点分析Spring中的核心容器.容器和Java容器不做详细介绍. [容器] 容器,从字面角度很容易理解,就是用来贮藏东西的.从计算机的角度,可粗略地分为Web容器和编程容器. Web容器是应用服务器中位于组件和平台之间的接口集合.如WebLogic.Tomcat等.

比Spring简单的IoC容器

比Spring简单的IoC容器 Spring 虽然比起EJB轻量了许多,但是因为它需要兼容许多不同的类库,导致现在Spring还是相当的庞大的,动不动就上40MB的jar包, 而且想要理解Spring的内部运行机制,阅读它的代码非常重要, 但是往往它的代码非常的"多". 现在根据Spring对Bean的生命周期的处理, 编写出一款非常小的IoC容器, 没有了对XML的解析,而是通过对Config对象的构造而完成IoC配置文件的声明, 相比较XML的方式, 对重构软件非常具有好处, 并且

Spring和SpringMVC父子容器关系所引发的血案

一.背景 最近在使用工具类实现将数据库中的数据批量导入到Solr索引库的时候,使用单元测试提示: java.lang.IllegalStateException: Failed to load ApplicationContext 在解决问题的过程中,偶然发现了Spring和SpringMVC是有父子容器关系的,正是由于这种父子容器关系的存在,导致了问题的存在. 二.错误重现 下面是我的测试类: public class SolrUtil { @Autowired private GoodsDa

Spring框架 之IOC容器 和AOP详解

主要分析点: 一.Spring开源框架的简介  二.Spring下IOC容器和DI(依赖注入Dependency injection) 三.Spring下面向切面编程(AOP)和事务管理配置  一.Spring开源框架的简介  Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来.它是为了解决企业应用开

0001 - Spring 框架和 Tomcat 容器扩展接口揭秘

前言 在 Spring 框架中,每个应用程序上下文(ApplicationContext)管理着一个 BeanFactory,BeanFactory 主要负责 Bean 定义的保存.Bean 的创建.Bean 之间依赖的自动注入等.应用程序上下文则是对 BeanFactory 和 Bean 的生命周期中的各个环节进行管理,并且提供扩展接口允许用户对 BeanFactory 和 Bean 的各个阶段进行定制,本文从以下三个点进行切入讲解. refresh()是应用上下文刷新阶段. getBean(