`
westlifesz
  • 浏览: 117540 次
社区版块
存档分类
最新评论

Spring 学习的笔记

阅读更多
 

Spring 开发指南笔记<o:p></o:p>

 <o:p></o:p>

Spring 基础语义<o:p></o:p>

 何谓控制反转(IoC = Inversion of Control),何谓依赖注入(DI = Dependency Injection)?概念所在:控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。<o:p></o:p>

相对IoC 而言,“依赖注入”的确更加准确的描述了这种古老而又时兴的设计理念。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。<o:p></o:p>

所谓依赖注入,即在运行期由容器将依赖关系注入到组件之中。讲的通俗点,就是在运行期,由Spring根据配置文件,将其他对象的引用通过组件的提供的setter方法进行设定。<o:p></o:p>

 <o:p></o:p>

 依赖注入的几种实现类型<o:p></o:p>

Ø         Type1 接口注入<o:p></o:p>

我们常常借助接口来将调用者与实现者分离。如:<o:p></o:p>

public class ClassA {<o:p></o:p>

private InterfaceB clzB;<o:p></o:p>

public doSomething() {<o:p></o:p>

Ojbect obj =<o:p></o:p>

Class.forName(Config.BImplementation).newInstance();<o:p></o:p>

clzB = (InterfaceB)obj;<o:p></o:p>

clzB.doIt()<o:p></o:p>

}<o:p></o:p>

……<o:p></o:p>

}<o:p></o:p>

上面的代码中,ClassA依赖于InterfaceB的实现,如何获得InterfaceB实现类的实例?传统的方法是在代码中创建InterfaceB实现类的实例,并将起赋予clzB<o:p></o:p>

而这样一来,ClassA在编译期即依赖于InterfaceB的实现。为了将调用者与实现者在编译期分离,于是有了上面的代码,我们根据预先在配置文件中设定的实现类的类名(Config.BImplementation),动态加载实现类,并通过InterfaceB强制转型后为ClassA所用。这就是接口注入的一个最原始的雏形。<o:p></o:p>

 <o:p></o:p>

而对于一个Type1型IOC容器而言,加载接口实现并创建其实例的工作由容器完成。<o:p></o:p>

如下面这个类:<o:p></o:p>

public class ClassA {<o:p></o:p>

private InterfaceB clzB;<o:p></o:p>

public Object doSomething(InterfaceB b) {<o:p></o:p>

clzB = b;<o:p></o:p>

return clzB.doIt();<o:p></o:p>

}<o:p></o:p>

……<o:p></o:p>

}<o:p></o:p>

在运行期,InterfaceB实例将由容器提供。<o:p></o:p>

 <o:p></o:p>

Ø         Type2 设值注入 (setter)<o:p></o:p>

在各种类型的依赖注入模式中,设值注入模式在实际开发中得到了最广泛的应用(其中很大一部分得力于Spring框架的影响)。在笔者看来,基于设置模式的依赖注入机制更加直观、也更加自然。Quick Start中的示例,就是典型的设置注入,即通过类的setter方法完成依赖关系的设置。<o:p></o:p>

Ø         Type3 构造子注入<o:p></o:p>

构造子注入,即通过构造函数完成依赖关系的设定,如:<o:p></o:p>

public class DIByConstructor {<o:p></o:p>

private final DataSource dataSource;<o:p></o:p>

private final String message;<o:p></o:p>

public DIByConstructor(DataSource ds, String msg) {<o:p></o:p>

this.dataSource = ds;<o:p></o:p>

this.message = msg;<o:p></o:p>

}<o:p></o:p>

……<o:p></o:p>

}<o:p></o:p>

可以看到,在Type3类型的依赖注入机制中,依赖关系是通过类构造函数建立,容器通过调用类的构造方法,将其所需的依赖关系注入其中。<o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

Spring Bean封装机制<o:p></o:p>

Spring 从核心而言,是一个DI 容器,其设计哲学是提供一种无侵入式的高扩展性框架。即无需代码中涉及Spring专有类,即可将其纳入Spring容器进行管理。<o:p></o:p>

作为对比,EJB则是一种高度侵入性的框架规范,它制定了众多的接口和编码规范,要求实现者必须遵从。侵入性的后果就是,一旦系统基于侵入性框架设计开发,那么之后任何脱离这个框架的企图都将付出极大的代价。为了避免这种情况,实现无侵入性的目标。Spring 大量引入了Java Reflection机制,通过动态调用的方式避免硬编码方式的约束,并在此基础上建立了其核心组件BeanFactory,以此作为其依赖注入机制的实现基础。<o:p></o:p>

org.springframework.beans包中包括了这些核心组件的实现类,核心中的核心为BeanWrapperBeanFactory类。这两个类从技术角度而言并不复杂,但对于Spring 框架而言,却是关键所在,如果有时间,建议对其源码进行研读,必有所获。<o:p></o:p>

所谓依赖注入,即在运行期由容器将依赖关系注入到组件之中。讲的通俗点,就是在运行期,由Spring根据配置文件,将其他对象的引用通过组件的提供的setter方法进行设定。<o:p></o:p>

 <o:p></o:p>

Bean相关包<o:p></o:p>

Spring 的核心是org.springframework.beans 包,为使用JavaBeans 技术、按名检索对象及管理对象间的关系而设计。beans包及其子包提供的功能为使用JavaBeans 技术的项目指定了一个基础设施。<o:p></o:p>

关于beans 包,有三个重要的概念。首先,它提供了设置/读取Javabeans 属性功能的BeanWrapper接口。第二个重要概念是Bean 工厂。BeanFactory 是一个泛化工厂,具有实例化对象和管理不同对象间关系的能力。BeanFactory 可以管理几种不同类型的bean,并且支持串行化及其他生命周期方法。BeanFactory 是按照bean 定义(BeanDefinition)来实例化对象的。BeanDefinition,顾名思义,是你对bean 的定义。BeanDefinition 不仅定义了bean 的类结构、实例化的方式,还定义了bean 在运行时的合作者。这是第三个概念。这三个概念( BeanFactory, BeanWrapper and BeanDefinition)将在下文详细讨论。<o:p></o:p>

对于org.springframework.beans 包遵循Sun 公司发布的JavaBeans 标准。所谓“JavaBean”其实就是一个Java 类。不过,它必须拥有默认无参数构造器,并按照既定规则来命名属性——属性prop对应一个设置器setProp(…)和读取器getProp(…)。更多的关于JavaBeans 的信息请查阅Sun 公司网站(java.sun.com/products/javabeans[http://java.sun.com/products/javabeans/]).<o:p></o:p>

 <o:p></o:p>

Bean Definitions

Bean definitions 是你的bean 的详细描述。Bean 就是一些提供某些特定功能的普通类,<o:p></o:p>

BeanFactory 接口如何管理你的bean 以及它们是怎样配置的,都是在一个bean definition 中规定的。以下就是bean definition 实际模型,这个模型使得bean definition 能够实例化bean。<o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

第一个例子以IoC 类型2(使用设置器)方式使用BeanFactory。下面是指定bean definition<o:p></o:p>

的部分XML 文件片断。你同样可以通过适当的设置器声明找到真正的bean。<o:p></o:p>

 <o:p></o:p>

applicationContext.xml片断:<o:p></o:p>

<bean id="exampleBean" class="examples.ExampleBean"><o:p></o:p>

<property name="beanOne"><ref bean="anotherExampleBean"/></property><o:p></o:p>

<property name="beanTwo"><ref bean="yetAnotherBean"/></property><o:p></o:p>

<property name="integerProperty">1</property><o:p></o:p>

</bean><o:p></o:p>

<bean id="anotherExampleBean" class="examples.AnotherBean"/><o:p></o:p>

<bean id="yetAnotherBean" class="examples.YetAnotherBean"/><o:p></o:p>

 <o:p></o:p>

public class ExampleBean {<o:p></o:p>

private AnotherBean beanOne;<o:p></o:p>

private YetAnotherBean beanTwo;<o:p></o:p>

private int i;<o:p></o:p>

public void setBeanOne(AnotherBean beanOne) {<o:p></o:p>

this.beanOne = beanOne;<o:p></o:p>

public void setBeanTwo(YetAnotherBean beanTwo) {<o:p></o:p>

this.beanTwo = beanTwo;<o:p></o:p>

public void setIntegerProperty(int i) {<o:p></o:p>

this.i = i;<o:p></o:p>

正如你所看到的,声明的设置器在XML 文件中被指定为一个相应的属性。(XML 文件中的属性直接与RootBeanDefinition 中定义的PropertyValues 相联系)。<o:p></o:p>

 <o:p></o:p>

客户端与factory 的交互<o:p></o:p>

客户端介面惊人的简单――BeanFactory 接口只有4 个方法与客户端交互<o:p></o:p>

Ø         Object getBean(String):按名返回一个已注册bean 的实例。取决于该bean 在BeanFactory 中的配置,将返回一个共享的唯一的bean 实例或者是一个重新创建的bean 实例。当无法找到bean的定义(此时将引发一个NoSuchBeanDefinitionException 异常)或者在进行实例化和初始化bean 时引发了一个异常,都将引起一个BeansException 异常被抛出。<o:p></o:p>

Ø         Object getBean(String,Class): 按名返回一个已注册bean 的实例。这个bean 实例的Class 类型必须和给出的Class 类型参数相匹配,否则相应的异常将会被抛出<o:p></o:p>

BeanNotOfRequiredTypeException 异常)将会被抛出。此外,这个方法的其他的行为和<o:p></o:p>

getBean(String)方法相同。(请参考getBean(String)方法)<o:p></o:p>

Ø         boolean isSingleton(String):按名检测已注册的beandefinition 是被设定为singleton 模式还是prototype 模式。如果给定的beandefinition 没有找到, 则抛出一个异常(NoSuchBeanDefinitionException 异常)<o:p></o:p>

Ø         String[] getAliases(String):返回某个已配置bean 的别名(TODO:这意味着什么?)<o:p></o:p>

 <o:p></o:p>

BeanFactory 的实现<o:p></o:p>

 <o:p></o:p>

XML 中指定bean 定义(XmlBeanFactory)<o:p></o:p>

BeanFactory 接口的一个实现是XmlBeanFactory 类(位于<o:p></o:p>

org.springframework.beans.factory.xml 包中)。正如它的名字所告诉你的,它为你提供了在XML文件中指定bean 定义的能力。Spring 提供了相应的DTD,使校验bean 定义XML 文件合法性的工作变得简单些。<o:p></o:p>

Spring XML bean 定义文档的根元素是<beans><beans>元素可以包含一个或多个bean 定义。我们通常指定每个bean 定义的类和属性。同时,我们也必须指定id――这是bean 的名字,我们将在代码中以这个名字使用这个bean。<o:p></o:p>

我们将使用Jakarta Commons DBCP 项目中的BasicDataSource 类。这个<o:p></o:p>

<v:line id="_x0000_s1026" style="Z-INDEX: 1; POSITION: absolute; flip: x; mso-position-horizontal: absolute; mso-position-vertical: absolute" coordsize="21600,21600" to="198pt,96.8pt" from="135pt,26.6pt"><v:stroke endarrow="block"></v:stroke></v:line>类(和其他很多早已存在的类一样)可以在Spring 轻松地使用,因为它提供了JavaBean 风格的配置方式。此类的实例在销毁前需要调用close 方法。这个方法通过Spring 的“destroy-method”attribute 在BeanFactory 中进行注册,而无需实现任何Spring 接口(否则你就需要实现早前在“生命周期特性”一节中提到的DisposableBean 接口)。<o:p></o:p>

<beans><o:p></o:p>

<bean id="myDataSource"<o:p></o:p>

class="org.apache.commons.dbcp.BasicDataSource"<o:p></o:p>

destroy-method="close"><o:p></o:p>

<!-- results in a setDriverClassName(String) call --><o:p></o:p>

<property name="driverClassName"><o:p></o:p>

<value>com.mysql.jdbc.Driver</value><o:p></o:p>

</property><o:p></o:p>

<property name="url"><o:p></o:p>

<value>jdbc:mysql://localhost:3306/mydb</value><o:p></o:p>

</property><o:p></o:p>

<property name="username"><o:p></o:p>

<value>root</value><o:p></o:p>

</property><o:p></o:p>

</bean><o:p></o:p>

</beans><o:p></o:p>

 <o:p></o:p>

就像使用destroy-method attribute 指定一个析构方法,我们可以使用init-method attribute指定一个初始化方法。<o:p></o:p>

 <o:p></o:p>

指定多个灵活属性,像list, properties 对象,或者Map 会出现两种可能。下面的例子展示了这种行为:<o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

 <o:p></o:p>

<v:shapetype id="_x0000_t75" coordsize="21600,21600" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id="_x0000_i1025" style="WIDTH: 483pt; HEIGHT: 257.25pt" type="#_x0000_t75"><v:imagedata cropright="4445f" cropleft="10486f" cropbottom="18594f" croptop="11027f" o:title="" src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msoclip1/01/clip_image002.png"></v:imagedata></v:shape><o:p></o:p>

<v:shape id="_x0000_i1026" style="WIDTH: 483pt; HEIGHT: 250.5pt" type="#_x0000_t75"><v:imagedata cropright="4445f" cropleft="10486f" cropbottom="18265f" croptop="12482f" o:title="" src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msoclip1/01/clip_image004.png"></v:imagedata></v:shape><o:p></o:p>

 <o:p></o:p>

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics