- 浏览: 59232 次
- 性别:
- 来自: 重庆
文章分类
最新评论
-
liuweihug:
Http请求状态及jquery ajax请求异常处理 - 前端 ...
springmvc ajax全局异常处理 -
hell_liul:
cargoj 写道quote="hell_liul& ...
ora-06530:未初始化的组合 -
cargoj:
quote="hell_liul"]hel ...
ora-06530:未初始化的组合 -
hell_liul:
hello,哥们,数组对象的返回值如何用java来调用呢??
ora-06530:未初始化的组合
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就可以了,不用修改主要的程式,从比较一般的角
度来看,就意味著如果您想要改变一些物件之间的依赖关系,则只要修改组态档即可,而不用修改组件
的任何一行程式。
发表评论
-
Struts2 jsonplugin JSONException
2012-04-26 20:19 990org.apache.struts2.json.JSONExc ... -
hibernate3 一对一映射延迟加载失效
2011-08-04 15:25 1403例子:新闻索引A表 内容B表,B在数据库中是CLOB类型。 ... -
Hibernate各种主键生成策略与配置详解(转)
2011-06-21 18:04 01、assigned 主键由外部程序负责生成,在 ... -
NullPointerException at com.opensymphony.xwork2.spring.SpringObjectFactory.getC
2011-06-03 17:23 2529at com.opensymphony.xwork2.spri ... -
『转载』struts2之ModelDriven
2011-05-30 16:42 1399可以根据Action属性的不 ... -
『转载』Struts2拦截器defaultStack与paramsPrepareParamsStack
2011-05-30 16:22 1269struts-default.xml中定义了一系列的拦截器和拦 ... -
拦截器和过滤器的区别『转载』
2011-05-30 11:39 1412很多人都了解过滤器也听说过拦截器,但是要是区分它们的不同点还真 ...
相关推荐
Spring 框架是Java开发领域中的一个核心框架,它主要设计目的是为了简化企业级应用的复杂性。Spring 自从2003年发布以来,因其强大的功能和灵活性,已经成为了许多开发者的首选。本节将详细介绍Spring的基本概念、...
Spring主要项目,从配置到安全,从Web应用到大数据 - 无论您的应用程序需要什么样的基础架构,都有一个Spring项目可以帮助您构建它。从小处着手,只使用你需要的东西 - Spring是模块化的设计。 Spring指南 无论您...
**Spring框架概述** Spring是一个广泛使用的Java开源框架,主要用于简化企业级应用的开发。它的核心设计理念是“简事简为,难事善为,重用轮子”,旨在提高开发效率,减少代码冗余,并促进代码的可维护性和可测试性...
01-spring简介-框架的概念Spring框架是 Java 平台的一个开源的全栈(Full-stack)应用程序框架和控制反转容器实现,一般被直接称为 Spring。该框架的一些核心功能理论上可用于任何 Java 应用,但 Spring 还为基于...
深入Spring简介与入门 Spring框架,作为Java世界中最具影响力的轻量级框架之一,自诞生以来便以其简洁、灵活的设计理念赢得了广大开发者的青睐。本文旨在深入探讨Spring框架的核心概念、架构设计及其在实际开发中的...
Spring简介+IOC(理论 Spring简介+IOC(理论 Spring简介+IOC(理论 Spring简介+IOC(理论 Spring简介+IOC(理论 Spring简介+IOC(理论
JAVA Spring 10、Spring简介.pdf
01Spring简介.md
1.spring简介.md
**Spring框架概述** Spring是一个开源的Java平台,它主要为构建企业级应用提供全面的解决方案。这个框架由Rod Johnson在2003年发起,旨在简化Java开发,尤其是在企业级应用开发中的复杂性。Spring的核心设计理念是...
Spring框架简介和基本原理 Spring是一个业界广泛采用的Java应用程序框架,旨在简化Java企业级应用程序的开发。 Spring框架的核心是容器(IoC容器),它提供了依赖注入(Dependency Injection)的机制,能够将应用...
Spring框架是Java开发中的一个重要组成部分,它由Rod Johnson创建,主要目标是解决企业级应用开发中的复杂性,尤其是对EJB(Enterprise JavaBeans)的过度依赖。Spring最初的理念源自于Rod Johnson的著作《Expert ...
### Java Spring 框架简介及相关面试题解析 #### Spring框架概述 Spring 是一款非常流行的开源Java企业级应用开发框架,被广泛应用于构建高性能、易测试及可复用的Java应用。该框架由Rod Johnson创建,并于2003年6...
在Spring之前我们写代码容易遇到高耦合问题,如下图所示,业务层的实现需要new一个数据层的对像,但是如果我们的数据层发生改变时,业务层的对象必须重新新建,重新进行编译、打包、部署,改动相对较多,代码耦合度...