`
cargoj
  • 浏览: 58131 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

Spring 简介

    博客分类:
  • SSH
阅读更多

01 - 简介 Spring
Spring是轻量级的J2EE应用程式框架。

 Spring的核心是个轻量级容器(container),实现了IoC(Inversion of Control)模式的容器,

Spring的目标是实现一个全方位的整合框架,在Spring框架下实现多个子框架的组合,这些子框架之间

彼此可以独立,也可以使用其它的框架方案加以替代,Spring希望提供one-stop shop的框架整合方案

 Spring不会特别去提出一些子框架来与现有的OpenSource框架竞争,除非它觉得所提出的框架够新够

好,例如Spring有自己的 MVC框架方案,因为它觉得现有的MVC方案有很多可以改进的地方,但它不强迫

您使用它提供的方案,您可以选用您所希望的框架来取代其子框架,例如您仍可以在Spring中整合您的

Struts框架。

 Spring的核心概念是IoC,IoC的抽象概念是「依赖关系的转移」,像是「高层模组不应该依赖低层模

组,而是模组都必须依赖於抽象」是IoC的一种表现,「实现必须依赖抽象,而不是抽象依赖实现」也是

IoC的一种表现,「应用程式不应依赖於容器,而是容器服务於应用程式」也是IoC的一种表现。

 IoC的概念与三种DI(Dependency Injection)类型在Martin Fowler的Inversion of Control

Containers and the Dependency Injection pattern中得到清楚的阐释,您可以先在以下的网址中了解

IoC与DI的详细说明:
http://www.martinfowler.com/articles/injection.html

 您也可以先看看这些文章,了解一下Dependency Inversion:
http://www.objectmentor.com/publications/dip.pdf

 Spring的核心即是个IoC/DI的容器,它可以帮程式设计人员完成组件(类别们)之间的依赖关系注入

(连结),使得组件(类别们)之间的依赖达到最小,进而提高组件的重用性,Spring是个低侵入性

(invasive)的框架,Spring中的组件并不会意识到它正置身於Spring中,这使得组件可以轻易的从框

架中脱离,而几乎不用任何的修改,反过来说,组件也可以简单的方式加入至框架中,使得组件甚至框

架的整合变得容易。

 Spring最为人重视的另一方面是支援AOP(Aspect-Oriented Programming),然而AOP框架只是Spring

支援的一个子框架,说Spring框架是AOP框架并不是一件适当的描述,人们对於新奇的 AOP关注映射至

Spring上,使得人们对於Spring的关注集中在它的AOP框架上,虽然有所误解,但也突显了Spring的另一

个令人关注的特色。

 Spring也提供MVC Web框架的解决方案,但您也可以将自己所熟悉的MVC Web框架与Spring解合,像是

Struts、Webwork等等,都可以与Spring整合而成为适用於自己的解决方案。

 Spring也提供其它方面的整合,像是持久层的整合如JDBC、O/R Mapping工具(Hibernate、iBATIS)

、事务处理等等,Spring作了对多方面整合的努力,故说Spring是个全方位的应用程式框架。

 想要入门Spring,对於IoC/D I的了解是必要的,上面的两个网址是个好的开始,另外您也可以先看

看「Spring开发指南」:
http://www.xiaxin.net/Spring_Dev_Guide.rar

 如果您想了解Spring的整体观念,可以看看Expert One on one J2EE Development Without EJB这本

书,Spring的前身是由该作者的前一本书Expert One on one J2EE Design and Development中的一个实

际程式开始,Spring本身是J2EE的一个轻量级容器解决方案,从这本书了解J2EE程式设计的考量也是个

不错的基础建构方式。

 当然,如果您时间有限,想直接了解Spring,可以从这篇文章开始:
http://javaboutique.internet.com/tutorials/spring_frame/

 对於Expert One on one J2EE Development Without EJB这本书,如果您想了解Spring,可以看

chapter 7、chapter 13。

其它的参考文章,可以看看这个分区的「Spring」资料中的连结。

 

 

02 - 控制反转IoC
IoC全名Inversion of Control,如果中文硬要翻译过来的话,就是「控制反转」。初看IoC,从字面上

不容易了解其意义,我觉得要了解IoC,要先从Dependency Inversion开始了解,也就是依赖关系的反转

 Dependency Inversion在下面这篇文章中有了清楚的解释:
http://www.objectmentor.com/publications/dip.pdf

 简单的说,在模组设计时,高层的抽象模组通常是与业务相关的模组,它应该具有重用性,而不依赖

於低层的实作模组,例如如果低层模组原先是软碟存取模式,而高层模组是个存档备份的需求,如果高

层模组直接叫用低层模组的函式,则就对其产生了依赖关系。

举个例子,例如下面这个程式:

#include <floppy.h>
....
void save() {
        ....
        saveToFloppy()
    }
}
 由於save()程式依赖於saveToFloppy(),如果今天要更换低层的存储模组为Usb碟,则这个程式没有办

法重用,必须加以修改才行,低层模组的更动造成了高层模组也必须跟著更动,这不是一个好的设计方

式,我们希望模组都依赖於模组的抽象,这样才可以重用高层的业务设计。

 如果以物件导向的方式来设计,依赖反转(Dependency Inversion)的解释变为程式不应依赖实作,

而是依赖於抽象,实作必须依赖於抽象。我们来看看下面这个Java程式:

BusinessObject.java
public class BusinessObject {
    private FloppyWriter writer = new FloppyWriter();
    ....
  
    public void save() {
        ...
        writer.saveToFloppy();
    }
}
 在这个程式中,BusinessObject的存档依赖於实际的FloppyWriter,如果今天我们想要将存档改为存

至Usb碟,我们必须修改或继承BusinessObject进行扩展,而无法直接使用BusinessObject。

如果透过介面的宣告,可以改进此一情况,例如:

public interface IDeviceWriter {
    public void saveToDevice();
}
public class BusinessObject {
    private IDeviceWriter writer;
    public void setDeviceWriter(IDeviceWriter writer) {
        this.writer = writer;
    }
    public void save() {
        ....
        writer.saveToDevice();
    }
}
 这样一来,BusinessObject就是可重用的,如果今天我有存储至Floppy或Usb碟的需求,我只要实作

IDeviceWriter即可,而不用修改BusinessObject:

public class FloppyWriter implement IDeviceWriter {
    public void saveToDevice() {
        ....
        // 实际储存至Floppy的程式码
    }
}
public class UsbDiskWriter implement IDeviceWriter {
    public void saveToDevice() {
        ....
        // 实际储存至UsbDisk的程式码
    }
}
 从这个角度来看,Dependency Inversion的意思即是程式不依赖於实作,而是程式与实作都要依赖於

抽象。

 IoC的Control是控制的意思,其实其背後的意义也是一种依赖关系的转移,如果A依赖於B,其意义即

是B拥有控制权,我们要转移这种关系,所以依赖关系的反转即是控制关系的反转,藉由控制关系的转移

,我们可以获得元件的可重用性,在上面的Java程式中,整个控制权从实际的 FloppyWriter转移至抽象

的IDeviceWriter介面上,使得BusinessObject、FloppyWriter、 UsbDiskWriter这几个实现依赖於抽象

的IDeviceWriter介面。

 从容器(Container)的角度,程式的业务逻辑部份应是可以重用的,不应受到所使用框架或容器的影

响,因为我们可能转移整个业务逻辑至其它的框架或容器,如果业务逻辑过於依赖容器,则转移至其它

的框架或容器时,就会发生困难。

 IoC在容器的角度,可以用这么一句好莱坞名言来代表:"Don't call me, I'll call you." 以程式的

术语来说的话,就是「不要向容器要求您所需要的(物件)资源,容器会自动将这些物件给您!」。IoC

要求的是容器不侵入应用程式本身,应用程式本身提供好介面,容器可以透过这些介面将所需的资源注

至程式中,应用程式不向容器主动要求资源,故而不会依赖於容器的元件,应用程式本身不会意识到正

被容器使用,可以随时从容器中脱离转移而不用作任何的修改,而这个特性正是一些业务逻辑中间件最

需要的。

 

 

03 - 依赖注入DI
IoC模式 基本上是一个高层的概念,在Martin Fowler的Inversion of Control Containers and the

Dependency Injection pattern中谈到,实现IoC有两种方式:Dependency Injection与Service

Locator。您可以在下面的网址中找到该篇文章:
http://www.martinfowler.com/articles/injection.html
 Spring所采用的是Dependency Injection来实现IoC,中文翻译为依赖注入,依赖注入的意义是:「保

留抽象介面,让组件依赖於抽象介面,当组件要与其它实际的物件发生依赖关系时,藉过抽象介面来注

入依赖的实际物件。」

 看看下面这个程式:

public class BusinessObject {
    private FloppyWriter writer = new FloppyWriter();
    ....
    public void save() {
        ...
        writer.saveToFloppy();
    }
}
 BusinessObject依赖於实际的FloppyWriter,为了让BusinessObject获得重用性,我们不让

BusinessObject依赖於实际的FloppyWriter,而是依赖於抽象的介面:

public interface IDeviceWriter {
    public void saveToDevice();
}
public class BusinessObject {
    private IDeviceWriter writer;
    public void setDeviceWriter(IDeviceWriter writer) {
        this.writer = writer;
    }
    public void save() {
        ....
        writer.saveToDevice();
    }
}
public class FloppyWriter implement IDeviceWriter {
    public void saveToDevice() {
        ....
        // 实际储存至Floppy的程式码
    }
}
public class UsbDiskWriter implement IDeviceWriter {
    public void saveToDevice() {
        ....
        // 实际储存至UsbDisk的程式码
    }
}
 如果今天BusinessObject想要与UseDiskWriter物件发生依赖关系,可以这么建立:

businessObject.setDeviceWriter(new UsbDiskWriter());
 由於BusinessObject依赖於抽象介面,在需要建立依赖关系时,我们可以透过抽象介面注入依赖的实

际物件。

 依赖注入在Martin Fowler的文章中谈到了三种实现方式:interface injection、setter injection

与constructor injection。并分别称其为type 1 IoC、type 2 IoC与type 3 IoC。

 上面的BusinessObject所实现的是type 2 IoC,透过setter注入依赖关系,而type 3 IoC,则在是建

构函式上注入依赖关系,例如:

public class BusinessObject {
    private IDeviceWriter writer;
    public BusinessObject(IDeviceWriter writer) {
        this.writer = writer;
    }
    public void save() {
        ....
        writer.saveToDevice();
    }
}
 Spring鼓励的是setter injection,但也允许您使用constructor injection,使用setter或

constructor来注入依赖关系视您的需求而定,使用constructor的好处之一是,您可以在建构物件的同

时一并完成依赖关系的建立,然而如果要建立的物件关系很多,则会在建构函式上留下一长串的参数,

这时使用setter会是个不错的选择,另一方面, setter可以有明确的名称可以了解注入的物件会是什么

,像是setXXX()这样的名称会比记忆constructor上某个参数位置代表某个物件来得好。

 Type 1 IoC是interface injection,使用type 1 IoC时会要求实作介面,这个介面是为容器所用的,

容器知道介面上所规定的方法,它可以呼叫实作介面的物件来完成依赖关系的注入,例如:

public interface IDependencyInjection {
    public void createDependency(Map dependObjects);
}
public class BusinessObject implement IDependencyInjection {
    private Map dependObjects;
    public void createDependency(Map dependObjects) {
        this.dependObject = dependObjects;
        // 在这边实现与BusinessObject的依赖关系
        ......
    }
    public void save() {
        ....
        writer.saveToDevice();
    }
}
 如果要完成依赖关系注入的物件,必须实现IDependencyInjection介面,并交由容器管理,容器会呼

叫被管理物件的createDependency()方法来完成依赖关系的建立。

 在上面的例子中,type 1 IoC要求BusinessObject实现特定的介面,这就使得BusinessObject依赖於

容器,如果日後BusinessObject要脱离目前这个容器,就必须修改程式,想想在更复杂的依赖关系中产

生更多复杂的介面,组件与容器(框架)的依赖会更加复杂,最後使得组件无法从容器中脱离。

 所以type 1 IoC具有强的侵入性,使用它来实现依赖注入会使得组件相依於容器(框架),降低组件

的重用性。

 Spring的核心是个IoC容器,您可以用setter或constructor的方式来实现您的业务物件,至於物件与

物件之间的关系建立,则透过组态设定,让Spring在执行时期根据组态档的设定来为您建立物件之间的

依赖关系,您不必特地撰写一些Helper来自行建立这些物件之间的依赖关系,这不仅减少了大量的程式

撰写,也降低了物件之间的耦合程度。

 

 

04 - 第一个Spring程式

 首先我们要先取得Spring的相关档案,Spring的档案放在SourceForge上,网址是:
http://sourceforge.net/project/showfiles.php?group_id=73357

 撰写此文时,Spring最新的版本是1.1.1,有两个下载版本,一个是spring-framework-1.1.1-with-

dependencies.zip,一个是spring-framework-1.1.1.zip,with-dependencies的包括一些 ant、

jakarta-commons、struts、velocity等等其它开源Java专案的相依档案,如果您也需要这些相关档案,

可以下载这个版本,如果您已经有这些相关档案,则只需要下载spring-framework-1.1.1.zip这个档案

 下载zip档案并解压缩之後,在dist目录下就是使用Spring所需要的相关档案,如果下载的是with-

dependencies版本,则在lib目录中的是您可能会用到的相依档案。在dist目录下,spring-core.jar是

Spring的核心,对於撰写简单的单机程式来说,使用这个核心即可,如果日後需要使用到Spring其它的

子框架支援,再将其它的jar档案加入即可,例如spring-aop.jar、spring- webmvc.jar等等。您也可以

直接使用spring.jar这个档案,它包括了所有Spring支援的功能所需要的所有类别,而不再需要加入个

别的 jar档案。

 就我们的第一个Spring程式,只要spring-core.jar这个档案即可,它唯一相依的其它专案档案,是

commons- logging.jar,您可以在lib目录的jakarta-commons目录中找到,将这两个档案的位置加入至

CLASSPATH中,我们就可以开始撰写第一个Spring程式。

 来撰写我们的第一个组件(component),它只是一个简单的JavaBean,用来向新的使用者打招呼:

HelloBean.java
package onlyfun.caterpillar;
public class HelloBean {
    private String helloWord = "Hello!World!";
  
    public void setHelloWord(String helloWord) {
        this.helloWord = helloWord;
    }
    public String getHelloWord() {
        return helloWord;
    }
}
 HelloBean有预设的"Hello!World!"字串,我们也可以透过setter来设定新的招呼语,不过我们不亲自

撰写程式来作这些事,而是在组态档案定义,由Spring来为我们作设定的动作,我们撰写bean.xml:

bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-

beans.dtd">
<beans>
    <bean id="helloBean" class="onlyfun.caterpillar.HelloBean">
        <property name="helloWord"><value>Hello!Justin!</value></property>
    </bean>
</beans>
 bean.xml中定义了JavaBean的别名与来源类别,<property>标签中设定了我们希望注入至JavaBean的

字串值,bean.xml必须在您的CLASSPATH可以存取到的目录中,也许是现行的工作目录,在Web程式中可

以是在classes目录下,我们这边使用的是单机程式的方式,将使用FileInputStream读取bean.xml,所

以将之置於现行的工作目录中,接著我们撰写一个简单的测试程式:

SpringTest.java
package onlyfun.caterpillar;
import java.io.*;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
public class SpringTest {
    public static void main(String[] args) throws IOException {
        InputStream is = new FileInputStream("bean.xml");
        BeanFactory factory = new XmlBeanFactory(is);
      
        HelloBean hello = (HelloBean) factory.getBean("helloBean");
        System.out.println(hello.getHelloWord());
    }
}

 这是从比较低层次的角度来使用Spring的IoC容器功能,藉由BeanFactory来读取组态档案并完成依赖

的关联注入,这边的依赖是什么?指的是 HelloBean相依於String物件,透过setter所保留的介面,我

们使用setter injection来完成这个依赖注入,而不是将招呼语写死在HelloBean,BeanFactory是整个

Spring的重点所在,整个 Spring的核心都围绕著它,在这边使用的是XmlBeanFactory,负责读取XML组

态档案,当然我们也可以使用properties档案,这之後会再介绍。

 BeanFactory读取Bean的组态设定并完成关系维护之後,我们可以藉由getBean()方法并指定Bean的别

名来取得实例,来看看实际运行之後的效果:

2004/10/21 上午 10:28:00 org.springframework.beans.factory.xml.XmlBeanDefinitionReader

loadBeanDefinitions
资讯: Loading XML bean definitions from resource for InputStream
2004/10/21 上午 10:28:00 org.springframework.beans.factory.support.AbstractBeanFactory

getBean
资讯: Creating shared instance of singleton bean 'helloBean'
Hello!Justin!
 如果今天您要想改变招呼语,则只要更改bean.xml就可以了,不用修改主要的程式,从比较一般的角

度来看,就意味著如果您想要改变一些物件之间的依赖关系,则只要修改组态档即可,而不用修改组件

的任何一行程式。

 

分享到:
评论

相关推荐

    Spring 简介 Spring 简介

    Spring 简介 Spring 简介

    Spring简介

    Spring主要项目,从配置到安全,从Web应用到大数据 - 无论您的应用程序需要什么样的基础架构,都有一个Spring项目可以帮助您构建它。从小处着手,只使用你需要的东西 - Spring是模块化的设计。 Spring指南 无论您...

    Spring简介(ppt)

    不错的文档,需要了解Spring的可以看下

    01-spring简介-框架的概念

    01-spring简介-框架的概念Spring框架是 Java 平台的一个开源的全栈(Full-stack)应用程序框架和控制反转容器实现,一般被直接称为 Spring。该框架的一些核心功能理论上可用于任何 Java 应用,但 Spring 还为基于...

    Spring简介+IOC(理论).ppt

    Spring简介+IOC(理论 Spring简介+IOC(理论 Spring简介+IOC(理论 Spring简介+IOC(理论 Spring简介+IOC(理论 Spring简介+IOC(理论

    JAVA Spring 10、Spring简介.pdf

    JAVA Spring 10、Spring简介.pdf

    01Spring简介.md

    01Spring简介.md

    spring简介

    spring简介关于怎样搭建框架了解三大框架得基本原理和应用

    深入Spring简介与入门

    深入Spring简介与入门,中软国际培训资料

    1.spring简介.md

    1.spring简介.md

    Spring简介.doc

    Spring致力于J2EE应用的各层的解决方案,而不是仅仅专注于某一层的方案。可以说Spring是企业应用开发的“一站式”选择,并贯穿表现层、业务层及持久层。然而,Spring并不想取代那些已有的框架,而与它们无缝地整合。

    Spring 简介 轻量级的J2EE 应用程序框架

    Spring 是轻量级的J2EE 应用程序框架。 Spring的核心是个轻量级容器(container),实现了IoC(Inversion of Control) 模式的容器,Spring的目标是实现一个全方位的整合框架,在Spring框架下实现多 个子框架的组合...

    中软国际Spring简介

    3天 第一天 Spring 基本概念(IOC) 第二天 AOP 第三天 Spring 整合Struts,Hibernate SSH

    spring简介-spring概念与体系结构

    在Spring之前我们写代码容易遇到高耦合问题,如下图所示,业务层的实现需要new一个数据层的对像,但是如果我们的数据层发生改变时,业务层的对象必须重新新建,重新进行编译、打包、部署,改动相对较多,代码耦合度...

    Spring简介和入门

    该ppt详细的对spring进行了介绍对初学者有很大的帮助啊。主要是介绍spring和入门

    Spring攻略PDF版

     第2章 Spring简介   2.1 Spring Framework   2.1.1 Spring的模块介绍   2.1.2 Spring的发布版本   2.1.3 Spring的项目   2.2 安装Spring Framework   2.2.1 问题描述   2.2.2 解决...

Global site tag (gtag.js) - Google Analytics