在本章中作者讲解了Spring的IoC概念,详细介绍了如何配置我们自己的应用系统,如何编写松耦合的组件。如何在XML中配置Bena。
这里提个建议,现在的Spring已经升级到2.0版本了,而本书(《Spring in Action》)出版时还是Spring1.X。2.0有了较大的变化建议新学Spring的人下载2.0版本的来学习,现在最新的版本已经是Rc3了。同时2.0版本的中文参考已经在Spring中文论坛有人组织翻译了。而且现在已经有预览版了,大家可以先参考一下。(Spring中文预览版:http://www.jactiongroup.net/reference2/html/)同时向无偿翻译Spring文档的这些高手们致敬。
一、容纳你的Bean
容器是Spring的核心。Spring使用IoC管理所有组成应用系统的组件。Spring有两种不同的容器:
l
l
1.BeanFactory介绍
在Spring中有几种BeanFactory的实现。其中最长用的是org.springframework.beans.factory.xml.XmlBeanFactory,它根据XML文件中的定义装载Bean。在XmlBeanFactory类中提供了两个构造函数,通常我们用的是XmlBeanFactory(Resource resource) throws BeansException这个。他一般这样定义:BeanFactory factory = new XmlBeanFactory(new FileSystemResource(“beans.xml”));其中传递的参数引用为:import org.springframework.core.io.FileSystemResource;(书中这里是不太正确的,因为在Spring2.0里已经不提供传递java.io.InputStream对象的构造函数了。翻译者非常的不负责任,应该在这里给出说明。)
从BeanFactory得到一个Bean只需调用getBean(“beanName”)方法,把你需要的Bean的名字当作参数传递进去就可以了。像这样:MyBean myBean = (MyBean)factory.getBean(“myBean”);当getBean()方法被调用的时候,工厂就会开始实例化Bean 并且使用依赖注入开始设置Bean的属性。
事实上BeanFactory接口提供有6种方法供客户代码调用:
(1)boolean containsBean(String): 如果BeanFactory包含符合给定名称的Bean定义或Bean实例,则返回true。
(2)Object getBean(String): 返回以给定名字注册的Bean实例。就是上面提到的最简单的一种。
(3)Object getBean(String, Class): 返回以给定名称注册的Bean,返回的Bean将被扔给(cast)给定的类。如果Bean不能被Cast,相应的异常(BeanNotOfRequiredTypeExc
(4)Class getType(String name): 返回给定名称的Bean的Class。如果没有相应于给定名称的Bean,则抛出NoSuchBeanDefinitionExce
(5)boolean isSingleton(String): 决定在给定名称时,Bean定义或Bean实例注册是否为单件模式,如果相应于给定名称的Bean不能被找到,则抛出NoSuchBeanDefinitionExce
(6)String[] getAliases(String): 如果在Bean的定义中有定义,则返回给定Bean名称的别名。
2.使用应用上下文(ApplicationContext)
使用ApplicationContext可以获得Sroing框架的强大功能。表面上ApplicationContext和BeanFactory差不多,但是ApplicationContext提供了更多的功能:
l
l
l
l
有三种ApplicationContext的实现经常被用到:
l
l
l
其中FileSystemXmlApplication
ApplicationContext context = new FileSystemXmlApplication
ApplicationContext context2 = new ClassPathXmlApplicationC
应用上下文会在上下文启动后预载入所有的单实例Bean。确保当你需要的时候他们已经准备好了你的应用不需要等待他们被创建。
总之实例化一个Bean大概有三种方法:
第一种:
Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
第二种:
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
第三种:
ApplicationContext context = new ClassPathXmlApplicationC
BeanFactory factory = (BeanFactory) context;
ApplicathionContext的超类是BeanFactory,所以理所当然的这里的context可以是BeanFactory。
3.Bean的生命周期
在书中作者用图文并茂的方式解说了Bean在BeanFactory和ApplicationContext中的生命周期,从创建到销毁的全过程。他们二者之间略有不同,书上讲的比较详细,这里就不罗列了。
二、基本装配
在Spring容器内拼凑Bean叫做装配。装配Bean的时候,你是在告诉容器需要哪些Bean以及容器如何使用依赖注入将他们配合在一起。
1.使用XML装配
Bean装配在Spring中最常用的是XML文件。在前面提到过的XmlBeanFactory、ClassPathXmlApplicationC
Spring规定了自己的XML文件格式,根元素为<Beans>,<Beans>有多个<Bean>子元素。每个<Bean>定义了一个Bean如何被装载到Spring容器中。看下面的名为test.xml的XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
</beans>
在Spring中,对一个Bean的最基本的配置包括Bean的ID和他的类全称。在test.xml文件中其中<Beans>为根元素,bean id=”foo”标明一个Bean他的Id为foo,此处的foo是由程序员自己命名的,但是在一个大的系统中有好多个Bean这里要求XML中的Id要唯一,在程序代码中如果想取得foo这个Bean就要用getBean(“foo”)了。class=”springinaction.foo”是Bean的全称类名。
2.添加一个Bean
Spring中的Bean在缺省情况下是单实例模式(也叫单态模式,http://blog.youkuaiyun.com/qutr/archive/2006/02/28/611868.aspx)。如果想每次从容器中得到得到一个Bean的不同实例,需要将Bean定义为原型模式(http://blog.youkuaiyun.com/qutr/archive/2006/07/24/968297.aspx)。我们可以用Bean的singleton属性来设置,缺省情况为true。
<bean id = "foo"
<bean id = "foo"
3.通过Set方法注入依赖。
写过JavaBean的人可能都熟悉get和set方法。Spring就是用Set注入来配置Bean的。<bean>的子元素<property>指明了使用它们的set方法来注入。你可以注入任何类型。
每个Bean(通常就是你定义的一个class)通常都会有一些简单的类型成员,如int或String等等。通过使用<property>的子元素<value>可以设置基本类型的属性(值)。
<bean id = "bar" class
</bean>
如上所示,在我们的springinaction.bar类中定义了一个名为barName的String类型的成员,用<value>coffeeBar</value>中的coffeeBar来给他设置值。如:setName(“barName”);如果定义了一个int类型的成员我们可以在<value></value>中写入一个数字。
利用property丰富的属性我们可以为一个Bean引用其它Bean,通过<ref>实现;可以嵌入一个内部Bean,通常很少使用。可以装配各种集合,如java.util.List, java.util.Set, java.util.Map等等。可以设置properties和null值。
下面给出一个例子,这个例子同样来自官方文档。
<bean id="moreComplexObject" class="example.ComplexObject">
</bean>
一目了然,非常清楚就不多解释了。关于集合Spring2.0又添加了新的内容,如:你如果使用的是JDK1.5那么还可以使用Java的泛型来清晰的解析各种容器所包含的类型,请参看:http://static.springframework.org/spring/docs/2.0.x/reference/beans.html#beans-collection-elements。
4.通过构造函数注入依赖
Set注入是Srping所推荐的,但是Set注入的缺点是,他无法清晰的表示出哪些属性是必须的,哪些是可选的。而使用构造函数注入的优势是通过构造函数来强制以来关系,有了构造函数的约束不可能实现一个不完全或无法使用的Bean。
<bean id="coo" class="springinaction.coo">
上面的例子通过构造函数传值来实例化一个coo对象。如coo co = new coo(“cool”);
如果有多个构造函数,那么可以设置<constructor-arg>的type或index来传入参数了如果类型都一样那么只能用index了,index的值是从0开始的。
Spring为我们提供了Set注入和构造函数注入,在两者的使用方式上个人有个人的理由和不同见解,在本书中作者给我们的建议大概是:看情况,那个合适用哪个(废话J)。但是,Spring的开发团队通常提倡人们使用setter注入。其实Spring一共给我提供了三种注入方式:接口注入和上面的两种注入。他们都有各自的优点,详细的说明见《Spring开发指南》。
下面再给出两个例子来说明一下Setter注入和constructor注入:
<bean id="exampleBean"
Spring提供了快捷的ref属性,来代替ref元素,但是使用ref属性你要小!
下面是一个类
publicclass ExampleBean
{
}
上面是一个Bean(其实就是一个普通的不能在普通的Java类)和它相对应的XML的配置文件,是一个典型的setter注入。例子清晰易懂就不多说了。
<bean id="exampleBean"
下面是一个类
publicclass ExampleBean
{
}
上面是一个Bean和它相对应的XML的配置文件,是一个典型的constructor注入。例子也比较清晰易懂这里也就不多说了。
三、自动装配
在前面讲到的都是手动显示装配Bean的方法,Spring还提供了自动装配Bean的方法。只要设置<Bean>的autowire属性。有四种自动装配类型:
l
l
l
l
如下实例:
在前面的显示装配:
<bean id="courseService"
下面是自动装配:
<bean id="courseService"
在Spring对Bean自动装配的过程中很容易出现不确定性,这些不确定性会导致程序无法运行。那么在我们的实际应用中要避免出现装配的不确定性。避免装配的不确定性的最好的方法就是使用显示装配和自动装配的混合方法。对有二义性的Bena使用显示装配,对没有二义性的Bean使用自动装配。
在通常情况下我们会分门别类的吧Bena设置在多个XML文件中。另外一种方法是使用一个或多个的<import/>(就像我们写Java程序要引入必要的包下的类一样)元素来从另外一个或多个文件加载Bean定义。需要注意的是:任何<import/>元素必须放在配置文件中的<bean/>元素之前以完成Bean定义的导入。如下示例:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
<beans/>
上例中,三行import引入了必要的XML文件。两行bean定义了Bean。依照XML的Schema或DTD,被导入文件必须是完全有效的XMLBean定义文件,且包含上层的<beans/>元素。
四、使用Spring的特殊Bean和应用举例
五、小结
其实关于Spring的IoC的核心和大部分内容在上面的文字中已经提到了,说来说去表面上就那些东西了。而IoC(DI)的真正思想是要靠大量的实践去体会和领悟的。