Spring 开发指南笔记
Spring 基础语义
何谓控制反转(IoC = Inversion of Control),何谓依赖注入(DI = Dependency Injection)?概念所在:控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
相对IoC 而言,“依赖注入”的确更加准确的描述了这种古老而又时兴的设计理念。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。
所谓依赖注入,即在运行期由容器将依赖关系注入到组件之中。讲的通俗点,就是在运行期,由Spring根据配置文件,将其他对象的引用通过组件的提供的setter方法进行设定。
依赖注入的几种实现类型
Ø Type1 接口注入
我们常常借助接口来将调用者与实现者分离。如:
public class ClassA {
private InterfaceB clzB;
public doSomething() {
Ojbect obj =
Class.forName(Config.BImplementation).newInstance();
clzB = (InterfaceB)obj;
clzB.doIt()
}
……
}
上面的代码中,ClassA依赖于InterfaceB的实现,如何获得InterfaceB实现类的实例?传统的方法是在代码中创建InterfaceB实现类的实例,并将起赋予clzB。
而这样一来,ClassA在编译期即依赖于InterfaceB的实现。为了将调用者与实现者在编译期分离,于是有了上面的代码,我们根据预先在配置文件中设定的实现类的类名(Config.BImplementation),动态加载实现类,并通过InterfaceB强制转型后为ClassA所用。这就是接口注入的一个最原始的雏形。
而对于一个Type1型IOC容器而言,加载接口实现并创建其实例的工作由容器完成。
如下面这个类:
public class ClassA {
private InterfaceB clzB;
public Object doSomething(InterfaceB b) {
clzB = b;
return clzB.doIt();
}
……
}
在运行期,InterfaceB实例将由容器提供。
Ø Type2 设值注入 (setter)
在各种类型的依赖注入模式中,设值注入模式在实际开发中得到了最广泛的应用(其中很大一部分得力于Spring框架的影响)。在笔者看来,基于设置模式的依赖注入机制更加直观、也更加自然。Quick Start中的示例,就是典型的设置注入,即通过类的setter方法完成依赖关系的设置。
Ø Type3 构造子注入
构造子注入,即通过构造函数完成依赖关系的设定,如:
public class DIByConstructor {
private final DataSource dataSource;
private final String message;
public DIByConstructor(DataSource ds, String msg) {
this.dataSource = ds;
this.message = msg;
}
……
}
可以看到,在Type3类型的依赖注入机制中,依赖关系是通过类构造函数建立,容器通过调用类的构造方法,将其所需的依赖关系注入其中。
Spring Bean封装机制
Spring 从核心而言,是一个DI 容器,其设计哲学是提供一种无侵入式的高扩展性框架。即无需代码中涉及Spring专有类,即可将其纳入Spring容器进行管理。
作为对比,EJB则是一种高度侵入性的框架规范,它制定了众多的接口和编码规范,要求实现者必须遵从。侵入性的后果就是,一旦系统基于侵入性框架设计开发,那么之后任何脱离这个框架的企图都将付出极大的代价。为了避免这种情况,实现无侵入性的目标。Spring 大量引入了Java 的Reflection机制,通过动态调用的方式避免硬编码方式的约束,并在此基础上建立了其核心组件BeanFactory,以此作为其依赖注入机制的实现基础。
org.springframework.beans包中包括了这些核心组件的实现类,核心中的核心为BeanWrapper和BeanFactory类。这两个类从技术角度而言并不复杂,但对于Spring 框架而言,却是关键所在,如果有时间,建议对其源码进行研读,必有所获。
所谓依赖注入,即在运行期由容器将依赖关系注入到组件之中。讲的通俗点,就是在运行期,由Spring根据配置文件,将其他对象的引用通过组件的提供的setter方法进行设定。
Bean相关包
Spring 的核心是org.springframework.beans 包,为使用JavaBeans 技术、按名检索对象及管理对象间的关系而设计。beans包及其子包提供的功能为使用JavaBeans 技术的项目指定了一个基础设施。
关于beans 包,有三个重要的概念。首先,它提供了设置/读取Javabeans 属性功能的BeanWrapper接口。第二个重要概念是Bean 工厂。BeanFactory 是一个泛化工厂,具有实例化对象和管理不同对象间关系的能力。BeanFactory 可以管理几种不同类型的bean,并且支持串行化及其他生命周期方法。BeanFactory 是按照bean 定义(BeanDefinition)来实例化对象的。BeanDefinition,顾名思义,是你对bean 的定义。BeanDefinition 不仅定义了bean 的类结构、实例化的方式,还定义了bean 在运行时的合作者。这是第三个概念。这三个概念( BeanFactory, BeanWrapper and BeanDefinition)将在下文详细讨论。
对于org.springframework.beans 包遵循Sun 公司发布的JavaBeans 标准。所谓“JavaBean”其实就是一个Java 类。不过,它必须拥有默认无参数构造器,并按照既定规则来命名属性——属性prop对应一个设置器setProp(…)和读取器getProp(…)。更多的关于JavaBeans 的信息请查阅Sun 公司网站(java.sun.com/products/javabeans[http://java.sun.com/products/javabeans/]).
Bean Definitions
Bean definitions 是你的bean 的详细描述。Bean 就是一些提供某些特定功能的普通类,
BeanFactory 接口如何管理你的bean 以及它们是怎样配置的,都是在一个bean definition 中规定的。以下就是bean definition 实际模型,这个模型使得bean definition 能够实例化bean。
第一个例子以IoC 类型2(使用设置器)方式使用BeanFactory。下面是指定bean definition
的部分XML 文件片断。你同样可以通过适当的设置器声明找到真正的bean。
applicationContext.xml片断:
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
public void setIntegerProperty(int i) {
this.i = i;
正如你所看到的,声明的设置器在XML 文件中被指定为一个相应的属性。(XML 文件中的属性直接与RootBeanDefinition 中定义的PropertyValues 相联系)。
客户端与factory 的交互
客户端介面惊人的简单――BeanFactory 接口只有4 个方法与客户端交互:
Ø Object getBean(String):按名返回一个已注册bean 的实例。取决于该bean 在BeanFactory 中的配置,将返回一个共享的唯一的bean 实例或者是一个重新创建的bean 实例。当无法找到bean的定义(此时将引发一个NoSuchBeanDefinitionException 异常)或者在进行实例化和初始化bean 时引发了一个异常,都将引起一个BeansException 异常被抛出。
Ø Object getBean(String,Class): 按名返回一个已注册bean 的实例。这个bean 实例的Class 类型必须和给出的Class 类型参数相匹配,否则相应的异常将会被抛出
(BeanNotOfRequiredTypeException 异常)将会被抛出。此外,这个方法的其他的行为和
getBean(String)方法相同。(请参考getBean(String)方法)
Ø boolean isSingleton(String):按名检测已注册的beandefinition 是被设定为singleton 模式还是prototype 模式。如果给定的beandefinition 没有找到, 则抛出一个异常(NoSuchBeanDefinitionException 异常)
Ø String[] getAliases(String):返回某个已配置bean 的别名(TODO:这意味着什么?)
BeanFactory 的实现
在XML 中指定bean 定义(XmlBeanFactory)
BeanFactory 接口的一个实现是XmlBeanFactory 类(位于
org.springframework.beans.factory.xml 包中)。正如它的名字所告诉你的,它为你提供了在XML文件中指定bean 定义的能力。Spring 提供了相应的DTD,使校验bean 定义XML 文件合法性的工作变得简单些。
Spring XML bean 定义文档的根元素是
我们将使用Jakarta Commons DBCP 项目中的BasicDataSource 类。这个
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
就像使用destroy-method attribute 指定一个析构方法,我们可以使用init-method attribute指定一个初始化方法。
指定多个灵活属性,像list, properties 对象,或者Map 会出现两种可能。下面的例子展示了这种行为: