Spring企业应用开发.ppt
Spring企业应用开发,Spring简介,本节课程目标,简介 Spring框架 J2EE架构的介绍Spring和EJB的比较?控制反转(Inversion of Control)概念介绍 依赖注入(Dependency Injection)概念介绍,Spring框架概述,Spring 是一个解决了许多在J2EE开发中常见的问题的强大框架。Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯。Spring的架构基础是基于使用JavaBean属性的 Inversion of Control容器。然而,这仅仅是完整图景中的一部分:Spring在使用IoC容器作为构建完关注所有架构层的完整解决方案方面是独一无二的。Spring提供了唯一的数据访问抽象,包括简单和有效率的JDBC框架,极大的改进了效率并且减少了可能的错误。Spring的数据访问架构还集成了 Hibernate和其他O/R mapping解决方案。,Spring框架概述,Spring还提供了唯一的事务管理抽象,它能够在各种底层事务管理技术,例如JTA或者JDBC事务提供一个一致的编程模型。Spring提供了一个用标准Java语言编写的AOP框架,它给POJOs提供了声明式的事务管理和其他企业事务-如果你需要-还能实现你自己的 aspects。这个框架足够强大,使得应用程序能够抛开EJB的复杂性,同时享受着和传统EJB相关的关键服务。Spring还提供了可以和IoC容器 集成的强大而灵活的MVC Web框架。,简介 Spring框架-什么是Spring框架?,Spring 的核心是个轻量级(Lightweight)容器(Container),实现了IoC(Inversion of Control)模式的容器,基于此核心容器所建立的应用程序,可以达到程序组件的松散耦合(Loose coupling),让程序组件可以进行测试(Testability),这些特性都使得整个应用程序可以在架构上与维护上都能得到相当程度的简化。,图解,Core 封装包是框架的最基础部分,提供IoC和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。构建于Core封装包基础上的 Context封装包,提供了一种框架式的对象访问方法,有些象JNDI注册器。Context封装包的特性得自于Beans封装包,并添加了对国际化(I18N)的支持(例如资源绑定),事件传播,资源装载的方式和Context的透明创建,比如说通过Servlet容器。,图解2,DAO 提供了JDBC的抽象层,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码。并且,JDBC 封装包还提供了一种比编程性更好的声明性事务管理方法,不仅仅是实现了特定接口,而且对所有的POJOs(plain old Java objects)都适用。ORM 封装包提供了常用的“对象/关系”映射APIs的集成层。其中包括JPA、JDO、Hibernate 和 iBatis。利用ORM封装包,可以混合使用所有Spring提供的特性进行“对象/关系”映射,如前边提到简单声明性事务管理。,图解3,Spring的 AOP 封装包提供了符合 AOP Alliance规范的面向方面的编程(aspect-oriented programming)实现,让你可以定义,例如方法拦截器(method-interceptors)和切点(pointcuts),从逻辑上讲,从而减弱代码的功能耦合,清晰的被分离开。而且,利用source-level的元数据功能,还可以将各种行为信息合并到你的代码中,这有点象.Net的attribute的概念。Spring中的 Web 包提供了基础的针对Web开发的集成特性,例如多方文件上传,利用Servlet listeners进行IoC容器初始化和针对Web的application context。当与WebWork或Struts一起使用Spring时,这个包使Spring可与其他框架结合。Spring中的 MVC 封装包提供了Web应用的Model-View-Controller(MVC)实现。Spring的MVC框架并不是仅仅提供一种传统的实现,它提供了一种 清晰的 分离模型,在领域模型代码和web form之间。并且,还可以借助Spring框架的其他特性。,简介 Spring框架-什么是Spring框架?,轻量级(Lightweight)Spring 的核心在档案容量上只有不到 1MB 的大小,而使用 Spring 核心所需要的资源也是很小的,而 Spring 是个非侵入性(Nonintrusive)框架,它的目的之一,是让应用程序不感受到框架的存在,减低应用程序从框架移植时的负担。容器(Container)Spring 核心本身是个容器,管理对象的生命周期、对象的组态、依赖式注入等,并可以控制对象在创建时是以 原型(Prototype)或 单例(Singleton)的方式来建立。,简介 Spring框架-什么是Spring框架?,IoC(Inversion of Control)Spring 的核心概念是IoC,更具体而易懂的名词是依赖注入(Dependency Injection),使用 Spring,您不必自己在程序代码中维护对象的依赖关系,只需在组态档中加以设定,Spring 核心容器会自动根据组态将依赖注入指定的对象。除了这些特性之外,Spring 的目标是实现一个全方位的整合框架,在 Spring 框架下实现多个子框架的组合,这些子框架之间彼此可以独立,也可以使用其它的框架方案加以替代,Spring 希望提供 one-stop shop 的框架整合方案。,简介 Spring框架-什么是Spring框架?,AOP 框架 Spring 最为人重视的另一方面是支持AOP(Aspect-oriented programming),然而 AOP 框架只是 Spring 支持的一个子框架,说 Spring 框架是 AOP 框架并不是一件适当的描述,人们对于新奇的 AOP 关注映射至 Spring 上,使得人们对于 Spring 的关注集中在它的 AOP 框架上,虽然有所误解,但也突显了 Spring 的另一个令人关注的特色。,简介 Spring框架-什么是Spring框架?,持久层 Spring 提供对持久层的整合,如 JDBC、O/R Mapping工具(Hibernate、iBATIS)、事务处理等。Web 框架 Spring 也提供 Web 框架的解决方案,但您也可以将自己所熟悉的 Web 框架与 Spring 整合,像是 Struts、Webwork等,都可以与 Spring 整合而成为适用于自己的解决方案。对于一些服务,例如 JNDI、Mail、排程、远程等,Spring不直接提供实作,而是采取抽象层方式进行包装,让这些服务在使用时可以有一致的使用模式且更为方便,什么是J2EE?,什么是J2EE,是业界标准有超过50家厂商实现了这些标准(工具,应用服务器)是各个厂商间协同工作的结果J2EE平台包括:共同认可的规范参考实现(Reference Implementation)测试套件(Test Suite)J2EE蓝本(Blueprints):设计指南基于Java技术 Java运行时环境(JRE)解释执行中间字节码(bytecode),J2EE架构的介绍,介绍J2EE的三层架构展现层-可以Struts框架持久化层-可以用Hibernate业务逻辑层-可以Spring注意:集成各种框架时,一定要注意各自的配置文件是怎么样的关系。Web.xmlstruts-config.xmlhibernate-config.xmlapplicationContext.xml,Spring和EJB比较?,Spring和EJB是什么关系Spring核心是依赖注入模式,它可以单机、或与现有应用服务器一起工作,使用了大量的XML配置EJB3.0是一个标准框架,它使用了大量的Java标注。Spring可以随时测试,而EJB测试非常麻烦预留作业:大家下去请寻找两者对比的详细资料,以便理解两者区别。,控制反转Inversion of Control,Spring 的核心概念是 IoC,IoC 的抽象概念是依赖关系的转移,像是高层模块不应该依赖低层模块,而是模块都必须依赖于抽象是 IoC 的一种表现,实现必须依赖抽象,而不是抽象依赖实现也是 IoC 的一种表现,应用程序不应依赖于容器,而是容器服务于应用程序也是 IoC 的一种表现。IoC 全名 Inversion of Control,如果中文硬要翻译过来的话,就是控制反转。初看 IoC,从字面上不容易了解其意义,我觉得要了解 IoC,要先从 Dependency Inversion 开始了解,也就是依赖关系的反转。理解核心:IoC就是将依赖关系进行了反转,要理解IoC,得先理解依赖关系,什么是依赖关系呢?,控制反转Inversion of Control,简单的说,在模块设计时,高层的抽象模块通常是与业务相关的模块,它应该具有重用性,而不依赖于低层的实作模块,例如如果低层模块原先是软盘存取模式,而高层模块是个存盘备份的需求,如果高层模块直接调用低层模块的函数,则就对低层模块产生了依赖关系。,控制反转Inversion of Control,举个例子,例如下面这个程序:public class CapterTest.void save().saveToFloppy();由于save()程序依赖于依赖于saveToFloppy(),如果今天要更换低层的存储模块为Usb盘,则这个程序没有办法重用,必须加以修改才行,低层模块的更动造成了高层模块也必须跟着更动,这不是一个好的设计方式,在设计上希望模块都依赖于模块的抽象,这样才可以重用高层的业务设计。,控制反转Inversion of Control,如果以对象导向的方式来设计,依赖反转(Dependency Inversion)的解释变为程序不应依赖实现,而是依赖于抽象,实现必须依赖于抽象。来看看下面这个 Java 程序:public class BusinessObject private FloppyWriter writer=new FloppyWriter();.public void save().writer.saveToFloppy();,控制反转Inversion of Control,在这个程序中,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();注意:红色部分是接口类型,而不是类,控制反转Inversion of Control,这样一来,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 的意思即是程序不依赖于实现,而是程序与实现都要依赖于抽象。,控制反转Inversion of Control,IoC 的 Control 是控制的意思,其实其背后的意义也是一种依赖关系的转移,如果A依赖于B,其意义即是B拥有控制权,您想要转移这种关系,所以依赖关系的反转即是控制关系的反转,藉由控制关系的转移,可以获得组件的可重用性,在上面的 Java 程序中,整个控制权从实际的 FloppyWriter 转移至抽象的 IDeviceWriter 接口上,使得BusinessObject、FloppyWriter、UsbDiskWriter 这几个实现依赖于抽象的 IDeviceWriter 接口。,控制反转Inversion of Control,程序的业务逻辑部份应是可以重用的,不应受到所使用框架或容器的影响,因为可能转移整个业务逻辑至其它的框架或容器,如果业务逻辑过于依赖容器,则转移至其它的框架或容器时,就会发生困难。IoC 在容器的角度,可以用这么一句好莱坞名言来代表:“Dont call me,Ill call you.”以程序的术语来说的话,就是不要向容器要求您所需要的(对象)资源,容器会自动将这些对象给您!。IoC 要求的是容器不侵入应用程序本身,应用程序本身提供好接口,容器可以通过这些接口将所需的资源注至至程序中,应用程序不向容器主动要求资源,故而不会依赖于容器的组件,应用程序本身不会意识到正被容器使用,可以随时从容器中脱离转移而不用作任何的修改,而这个特性正是一些业务逻辑中间件最需要的。,依赖注入Dependency Injection,IoC模式基本上是一个高层的概念,在 Martin Fowler 的 Inversion of Control Containers and the Dependency Injection pattern 中谈到,实现IoC有两种方式:依赖注入Dependency InjectionService Locator,Spring 所采用的是Dependency Injection 来实现 IoC,中文翻译为依赖注入,依赖注入的意义是:保留抽象接口,让组件依赖于抽象接口,当组件要与其它实际的对象发生依赖关系时,借助抽象接口来注入依赖的实际对象。,依赖注入Dependency Injection,看看下面这个程序:public class BusinessObject private FloppyWriter writer=new FloppyWriter();.public void save().writer.saveToFloppy();,依赖注入Dependency Injection属性注入,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();,依赖注入Dependency Injection,public class FloppyWriter implement IDeviceWriter public void saveToDevice()./实际储存至Floppy的程序代码 public class UsbDiskWriter implement IDeviceWriter public void saveToDevice()./实际储存至UsbDisk的程序代码,依赖注入Dependency Injection,如果今天BusinessObject想要与UseDiskWriter对象发生依赖关系,可以这么建立:businessObject.setDeviceWriter(new UsbDiskWriter();由于BusinessObject依赖于抽象接口,在需要建立依赖关系时,可以通过抽象接口注入依赖的实际对象。,依赖注入有几种实现方式?,依赖注入在Martin Fowler的文章中谈到了三种实现方式:Interface injection-接口注入Setter injection-属性注入 Constructor injection-构造函数注入并分别称其为:Type 1 IoC Type 2 IoC Type 3 IoC,依赖注入Dependency Injection构造函数注入,上面的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();,依赖注入Dependency Injection,Spring 鼓励的是 Setter injection,但也允许您使用 Constructor injection,使用 Setter 或 Constructor 来注入依赖关系视您的需求而定,使用 Constructor 的好处之一是,您可以在构造对象的同时一并完成依赖关系的建立,然而如果要建立的对象关系很多,则会在构造式上留下一长串的参数,这时使用 Setter 会是个不错的选择,另一方面,Setter 可以有明确的名称可以了解注入的对象会是什么,像是setXXX()这样的名称会比记忆Constructor上某个参数位置代表某个对象来得好。,依赖注入Dependency Injection接口注入,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();,依赖注入Dependency Injection,如果要完成依赖关系注入的对象,必须实现IDependencyInjection接口,并交由容器管理,容器会呼叫被管理对象的createDependency()方法来完成依赖关系的建立。在上面的例子中,Type 1 IoC要求BusinessObject实现特定的接口,这就使得BusinessObject依赖于容器,如果日后BusinessObject要脱离目前这个容器,就必须修改程序,想想在更复杂的依赖关系中产生更多复杂的接口,组件与容器(框架)的依赖会更加复杂,最后使得组件无法从容器中脱离。所以Type 1 IoC具有强的侵入性,使用它来实现依赖注入会使得组件相依于容器(框架),降低组件的重用性。,依赖注入三种方式比较,构造函数注入和属性注入本质上很类似,业务对象(或称领域对象)BusinessObject不需要继承实现持久层的接口IDeviceWriter,它只需要拥有该接口的一个实例成员即可IDeviceWriter只需关注自己的持久化实现,无需关注业务对象接口注入却不同,它要求业务对象(或称领域对象)BusinessObject必须实现持久层的接口IDeviceWriter,借助实现接口的函数方法来进行依赖注入。接口注入有很强的侵入性,它侵入了业务对象(或领域对象)内部它要求业务对象内部依赖的对象是通过接口内的方法的参数传递的构造函数注入和接口注入都是利用了函数参数的传递方式进行注入的,即在函数方法内部实现依赖对象的传递,依赖注入Dependency Injection,Spring的核心是个IoC容器,您可以用Setter或Constructor的方式来实现您的业务对象,至于对象与对象之间的关系建立,则通过类型设定,让Spring在执行时期根据类型文件的设定来为您建立对象之间的依赖关系,您不必特地撰写一些Helper来自行建立这些对象之间的依赖关系,这不仅减少了大量的程序编写,也降低了对象之间的耦合度。,主讲:吴成浩Email:,