1.2 IOC容器基本原理
在没有使用IOC容器之前,我们在程序内部通过new关键字创建对象(bean)并管理对象之间的关系。使用了IOC容器之后,创建对象和管理对象之间关系的工作由IOC容器来负责,控制权从程序内部转换到了IOC容器,所以称为控制反转。
在Spring中,那些组成应用程序的主体及由Spring IOC容器所管理的对象,被称为bean。简单地讲,bean就是由Spring IOC容器初始化、装配及管理的对象(见图1.2)。除此之外,bean就与应用程序中的其他对象没有什么区别了,而bean定义以及bean相互间的依赖关系将通过配置元数据来描述。
图1.2 Spring IOC容器
1.2.1 配置元数据
从图1.2中可以看到,Spring IOC容器将读取配置元数据,并通过它对应用中各个对象进行实例化、配置以及组装。通常情况下,我们使用简单直观的XML文件作为配置元数据的描述格式。在XML配置元数据中,我们可以对那些希望通过Spring IOC容器管理的bean进行定义。
下面是XML配置元数据的基本结构。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="..."class="..."> <!--该bean的协作者及其他配置 --> </bean> <bean id="..."class="..."> <!--该bean的协作者及其他配置 --> </bean> <!-- 更多的bean配置 --> </beans>
在顶层的beans元素中配置一个或多个bean元素。
在配置文件中定义bean元素对应于在应用程序中创建bean对象。通常情况下这些bean包括:类似Struts Action的表示层(Action层)对象、服务层(Service层)对象、数据访问层(DAO层)对象、Hibernate SessionFactory对象、JMS Queue对象等。
bean元素的id属性给bean指定标识符,class属性是类的全限定类名。当使用XML文件配置元数据时,可通过id或name属性来给bean指定标识符。id属性具有唯一性,而且是一个真正的XML id属性,因此其他XML元素在引用该id时,可以利用XML解析器的验证功能(如Eclipse会验证XML元素的id唯一性和引用的id是否存在)。通常情况下,最好为每个bean指定一个id,为了给一个bean提供多个名称,可以在name属性中使用逗号、冒号或者空格将多个名称分隔,而所有的这些名称都指向同一个bean,因为在某些情况下提供这些别名非常有用。
1.2.2 实例化容器
● 添加jar包
实例化容器需要在程序代码中使用Spring API,所以在写代码之前,需要将下列的jar包添加到项目的classpath下。
org.springframework.core-3.1.4.RELEASE.jar org.springframework.beans-3.1.4.RELEASE.jar
另外还有些依赖的jar包也需要被加入。
commons.logging-1.1.1.jar
这些jar包都可以在Spring的发布版本中找到。
● 编写配置文件
做好准备之后,需要在工程的src目录下新建一个XML文档,命名为beans.xml,这就是前面提到的配置文件,在其中输入以下的内容:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="expBean" class="org.bd.spring.ch01.ExampleBean"> <!--该bean的协作者及其他配置 --> </bean> <!-- 更多的bean配置 --> </beans>
其中,org.bd.spring.ch01.ExampleBean是随意建立的一个类,大家可以依此方法定义自己的类。
● 实例化容器
public class UseContainer { public static void main(String[] args) { //加载classpath下的beans.xml,实例化容器 BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml")); //按name或id获取实例 ExampleBean bean = factory.getBean("expBean",ExampleBean.class); //使用bean System.out.println(bean); } }
上述代码中需要进行如下说明。
(1)org.springframework.beans.factory.BeanFactory是Spring IOC容器的实际代表者,IOC容器负责容纳此前所描述的bean,并对bean进行管理。在Spring中,BeanFactory是IOC容器的核心接口。它的职责包括实例化、定位、配置应用程序中的对象并建立这些对象间的依赖。Spring为我们提供了许多易用的BeanFactory实现,XmlBeanFactory就是最常用的一个。
(2)在大多数的应用程序中,并不需要用显式的代码去实例化一个或多个Spring IOC容器实例,只是在开始的学习阶段使用这种方法。
(3)BeanFactory的getBean()方法用bean的标识从容器中获取实例,该实例和用new关键字创建的实例并无区别,可以想象成IOC容器帮我们执行了实例化的动作。
1.2.3 使用ApplicationContext
ApplicationContext是BeanFactory的扩展,功能得到了进一步增强,比如更易与Spring AOP集成、资源处理(国际化处理)、事件传递及各种不同应用层的context实现(如针对Web应用的WebApplicationContext)。
简而言之,BeanFactory提供了基本功能,而ApplicationContext则增加了更多支持企业核心内容的功能。ApplicationContext完全由BeanFactory扩展而来,因而BeanFactory所具备的能力和行为也适用于ApplicationContext。
一般情况下,我们把ApplicationContext接口作为使用IOC容器类的首选。使用ApplicationContext需要添加以下的jar包。
org.springframework.context-3.1.4.RELEASE.jar org.springframework.asm-3.1.4.RELEASE.jar org.springframework.expression-3.1.4.RELEASE.jar
下面的代码示范了ApplicationContext的使用。
//加载classpath下的beans.xml,实例化容器 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); ExampleBean bean = context.getBean("expBean",ExampleBean.class); System.out.println(bean);
1.2.4 bean的实例化
从本质上来说,XML配置文件中bean的定义描述了如何创建一个或多个对象实例。当需要的时候,容器会从bean定义列表中取得一个指定的bean定义,并根据bean定义的具体内容使用反射机制来创建(或取得)一个实际的对象。
具体来说,XML配置文件中bean元素的class属性指明了将被实例化的对象的类型。class属性通常是必需的,它有两种用途。在大多数情况下,容器将直接通过反射调用指定类的构造器来创建bean实例(类似于在Java代码中使用new操作符)。在极少数情况下,容器将调用类的静态工厂方法来创建bean实例,class属性将用来指定具有静态工厂方法的类。
● 使用静态工厂方法实例化bean
当采用静态工厂方法创建bean实例时,除了需要指定class属性外,还需要通过factory-method属性来指定创建bean实例的工厂方法,Spring将调用此方法返回实例对象。
<bean id="expBean2" class="org.bd.spring.ch01.ExampleBean2" factory-method="createInstance"> </bean>
ExampleBean2类中必须有静态的createInstance方法,具体代码如下:
public class ExampleBean2 { public static ExampleBean2 createInstance(){ return new ExampleBean2(); } }
这种方式在实际开发中并不多见,因此以后将不对此方法展开讨论。