Spring学习笔记

spring概述 Spring项目启动于2003年2月,其中基础代码来自《expert one-on-one j2ee design and development》。 Spring 是指一个用于构造Java 应用程序的轻量级框架,不限定于只编写web 应用,最少侵入。 Spring 的核心是个轻量级(Lightweight)的容器(Container),它是实现IoC(Inversion of Control)容器、非侵入性(No intrusive)的框架,并提供AOP(Aspect-oriented programming)概念的实现方式,提供对持久层(Persistence)、事务(Transaction)的支持,提供MVC Web 框架的实现,并对一些常用的企业服务API(Application Interface)提供一致的模型封装,是一个全方位的应用程序框架(Application framework),除此之外,对于现存的各种框架(Struts、JSF、Hibernate 等),Spring 也提供了与它们相整合的方案。 本质上讲,Spring是IOC(Inversion of Control)和面向切面编程(AOP)的组合体。它是一个非侵入式的框架,增强了POJO的功能。从服务上讲(With a service abstraction),它将程序代码从J2EE环境解耦到普通的java对象(自然,这些代码可以脱离J2EE而在多种环境中运行)。它还在很多功能上提供了除EJB之外的选择――比如为所有的POJO提供声明式事务。Spring被广泛运用到很多项目中,从小的web程序到大的企业应用程序。 控制反转,还是依赖注入 Spring 框架的核心基于“控制反转(Inversion of Control,IoC)”原理。IoC 是一种将组件依赖关系的创建和管理置于程序外部的技术。假设一个例子,类Foo 依赖于类Bar 的一个实例来进行某些操作。传统的方式,Foo 使用new 操作符创建一个Bar 的实例,或者通过某种工厂类来获得。使用IoC 方法,Bar 的一个实例(或者其子类的实例)是通过某些外部处理过程在运行时动态传递给Foo 的。这种在运行时注入依赖的行为方式,使得IoC 后来被改称为另一个含义更明确的名字:“依赖注入(Dependency Injection ,DI)”。 Spring 的DI 实现是基于两个Java 核心概念:JavaBean 和Interface。当你使用DI 的时候,你可以使得依赖配置与你的代码保持隔离。JavaBeans 提供了一种创建Java 资源的标准方法,并且这些资源是可以通过标准方式配置的。 接口与DI 是相互受益的技术,针对接口设计与编程有助于应用程序的灵活性,但要把采用接口设计的应用程序的各部分连接起来,其复杂度非常高,并且给开发者带来了额外的编码负担。通过采用DI,为基于接口的设计而编写的辅助代码大大减少了,近乎于零。反过来,通过采用接口,你可以获得DI 的最大好处,因为你的bean 可以采用任何满足其依赖的接口实现。 减少“粘合”代码:DI 带来的最大的好处之一就是,它可以奇迹般地消除你为了连接应用程序的各个部件而编写的大量代码。这些代码常常很简单而且琐碎——通过构造一个新的对象来创建依赖。然而,当你需要从JNDI 库中查询依赖,或者这些调用不能直接通过调用产生时(比如访问远程资源),这些琐碎的代码可能会变得相当复杂。在这些情形下,DI 真的可以简化粘合代码,因为它提供了自动的JNDI 查询,以及对远程资源的自动代理。 依赖外置化:你可以将依赖的配置外置,这样你可以无需重新编译代码就重新配置。这给你带来两个有趣的好处。首先, Spring 中的DI 是一种理想的配置方式,可以让你在外部自由的配置应用程序的所有选项。其次,依赖外置使得在不同的实现间切换变得非常容易。假设你有一个DAO 组件,它针对PostgreSQL 数据库进行数据操作,你想把它升级到Oracle。使用DI,你可以简单地重新配置你的业务对象的依赖关系,让它使用Oracle 实现而非PostgreSQL 实现。 在统一的地方管理依赖:采用传统的方式管理依赖时,你在任何需要的地方创建依赖的对象实例——就在依赖者的内部。在大部分简单的程序中,你会让依赖关系在你的代码中散播,改变它们通常会带来问题。当使用DI 的时候,所有关于依赖的信息都通过一个简单的库进行管理,使得管理依赖变得既简单又不容易出错。 提高可测试性:当面向DI 设计你的类时,你就可以便捷地替换依赖。当在测试程序的时候,这特别有用。假设一个业务对象进行某些复杂的处理,其中一部分它使用一个DAO 对象来访问存储在关系数据库中的对象。在测试的时候,你对测试DAO 本身不感兴趣,你只是简单地希望采用不同的数据集来测试你的业务对象。在通常的方式中,你的测试会变得很痛苦,因为你无法简单地把这个DAO 实现替换为一个模拟实现,模拟返回你的测试数据。相反,你需要确认你的测试数据库中包含正确的数据,为你的测试使用完整的DAO 实现。使用DI 的话,你可以为你的DAO 对象创建一个模拟实现,然后把它传递给你的业务对象进行测试。这种机制可以扩展到测试你的应用的任何一层,对测试web 组件特别有用,你可以创建HttpServletRequest 和HttpServeletResponse 的模仿实现。 鼓励良好的程序设计:针对DI 设计意味着整体上针对接口设计。典型的基于注入的应用程序,其所有的主要组件都是定义为接口的,然后这些接口的具体实现采用DI 容器创建并糅合到一起。在DI 和基于DI 的容器比如Spring 出现之前,这种设计在Java 中就是可行的,但是通过使用Spring,你免费获得了一个包含完整DI 功能的基础,你可以集中精力于建立你的业务逻辑,而非关注支持业务的框架。 面向方面编程 AOP 提供了实现横切逻辑的功能——这一逻辑应用于你应用程序的很多地方,只需要编写一次,就可以把这一逻辑自动在整个应用中实施目前有两种主流的AOP 实现。静态AOP,比如AspectJ (www.apsectj.org),提供了编译器的方法来构建基于AOP 的逻辑,并把它加入到应用程序中。动态AOP,比如Spring 中的这样,允许在运行时把横切逻辑应用到任意一段代码中。两种不同的AOP 方法都有其适用面,实际上,AOP 提供了与AspectJ 整合的功能。 一致性抽象 异常 资源管理 事务管理 事务管理Spring 提供了极好的事务管理抽象层,允许你进行编程式或者声明式事务控制。通过使用Spring 的抽象层来进行事务,你可以很容易地抽换底层的数据访问协议和资源管理方式。你可以从一个简单的、本地的、单资源的事务管理起步,转移到全局的、多资源的事务管理环境,而无需更改你的代码。 测试 与其它框架整合 在Spring 中访问数据 Spring 中的JDBC 支持使得编写基于JDBC 的应用变得更加现实了,就算是比较复杂的应用程序也行。对Hibernate、iBATIS 和JDO 的支持让本就简单的API 更加简化,减轻了开发者的负担,易于在同一程序中混合不同的数据访问技术。 简化与整合J2EE Web层的MVC 远程访问(Remoting)支持 Mail支持 计划任务支持 简化的异常处理 源代码级的Metadata(元数据) 控制反转 容器(container) 是指应用代码的运行框架。 提供服务: 生命周期管理 查找服务 配置服务 依赖决议 理想容器特点: 可接插性 一致性 一站式购物 提供企业级服务 IoC类型 type name description Type1 Interface dependent Beans must implement specific interfaces to have their dependencies managed by the container. Type2 Setter injection Dependencies and properties are configured through a bean’s setter methods. Type3 Constructor injection Dependencies and properties are configured through the bean’s constructor. 依赖注入的基本原则:应用对象不应该负责查找资源或者其他依赖的协作组件。配置对象的工作应该由IoC容器完成,“查找资源”的逻辑应该从应用代码中抽取出来,交给容器负责。 接口方法注入:组件通过接口的方式完成注入,具备侵入性,它要求组件必须与特定的接口相关联,因此并不被看好,实际使用有限。 设值方法注入:组件通过javabean属性来表达自己需要配置的值和依赖的对象,建立在javabean规范之上。 构造子注入:组件以构造子参数的形式描述自己需要的依赖关系。 IoC in spring Spring的IoC控件主要专注于如何利用classes、对象和服务去组成一个企业级应用,通过规范的方式,将各种不同的控件整合成一个完整的应用。Spring中使用了很多被实践证明的最佳实践和正规的设计模式,并且进行了编码实现。如果你是一个,构架师或者开发人员完全可以取出它们集成到你自己的应用之中。这对于那些使用了Spring Framework的组织和机构来说,在spring基础上实现应用不仅可以构建优秀的,可维护的应用并对Spring的设计进行验证,确实是一件好事情。 Spring框架所提供的众多功能之所以能成为一个整体正是建立在IoC的基础之上,org.springframework.beans及org.springframework.context包是Spring IoC容器的基础。BeanFactory提供的高级配置机制,使得管理任何性质的对象成为可能。ApplicationContext是BeanFactory的扩展,功能得到了进一步增强,比如更易与Spring AOP集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的context实现(如针对web应用的WebApplicationContext)。 简而言之,BeanFactory提供了配制框架及基本功能,而ApplicationContext则增加了更多支持企业核心内容的功能。ApplicationContext完全由BeanFactory扩展而来,因而BeanFactory所具备的能力和行为也适用于ApplicationContext。  用户注册的例子 我们先看看更进一步的需求:实现一个用户注册信息持久化的类。 功能: 1、 保存用户注册的信息; 2、 根据用户的名称获得该注册用户。 虽然功能简单,但它对持久化方式的要求却非常的灵活: 1、 在内存中持久化,供测试、演示使用。 2、 如果用户的数据很少,将用户信息持据化到文本文件中。 3、 如果用户信息很多,并需要一些灵活的查询,则需要使用JDBC技术将用将用户信息持久化到数据库中。 4、 面对企业复杂关联的数据,甚至需要使用持久层框架来实现用户信息的持久化,比如:iBATIS、Hibernate等。 如何去设计、实现我们这个持久化类呢? 我们遵循软件开发的原则“首先让它跑起来,再去优化(重构)它”,我们首先实现最简单的在内存中持久化用户信息。 既然我们要保存和取得用户信息,首先应该设计用户类。代码如下: User.java public class User { private Long id; private String name; private String password; private String group; public User(String name,String password){ this.name = name; this.password = password; } //相应的get/set方法 ……….. } 持久化类有两个方法,分别在内存中保存和获取User对象。代码如下: MemoryUserPersist.java public class MemoryUserPersist { private static Map users = new HashMap(); static{ User defaultAdmin = new User(\"Moxie\",\"pass\"); users.put(defaultAdmin.getName(),defaultAdmin); } public MemoryUserPersist (){ } public void saveUser(User user){ users.put(user.getName(),user); } public User LoadUser(String userName){ return (User)users.get(userName); } } 用户持久化类完成之后,我们就可以在客户端UserRegister中使用它了。例如:用户注册时,UserRegister代码片断如下: MemoryUserPersist userPersist = new MemoryUserPersist (); userPersist.saveUser(user); 可是,现在如果要在文本文件中持久化User,又该如何实现呢?实现一个TextUserPersist类,这个并不困难。但客户端代码将面临重大灾难:找到所有使用过MemoryUserPersist的客户端类,将他们中的MemoryUserPersist逐个手工修改为 TextUserPersist,并且重新编译,当然以前的测试也必须全部从头来过! 人生的浩劫只是刚刚开始,因为根据前面的需求我们至少要分别实现四种持久化方式!这时,你一定和我一样在期待着救世主的早日降临——接口(Interface)。  面向接口编程 什么是接口? • 接口定义了行为的协议,这些行为在继承接口的类中实现。 • 接口定义了很多方法,但是没有实现它们。类履行接口协议并实现所有定义在接口中的方法。 • 接口是一种只有声明没有实现的特殊类。 接口的优点: • Client不必知道其使用对象的具体所属类。 • 一个对象可以很容易地被(实现了相同接口的)的另一个对象所替换。 • 对象间的连接不必硬绑定(hardwire)到一个具体类的对象上,因此增加了灵活性。 • 松散藕合(loosens coupling)。 • 增加了重用的可能性。 接口的缺点: 设计的复杂性略有增加  重构第一步——面向接口编程 1、 设计用户持久化类的接口UserDao,代码如下: public interface UserDao { public void save(User user); public User load(String name); } 2、 具体的持久化来必须要继承UserDao接口,并实现它的所有方法。我们还是首先实现内存持久化的用户类: public class MemoryUserDao implements UserDao{ private static Map users = new HashMap();; static{ User user = new User(\"Moxie\",\"pass\"); users.put(user.getName(),user); } public void save(User user) { users.put(user.getId(),user); } public User load(String name) { return (User)users.get(name); } } MemoryUserDao的实现代码和上面的MemoryUserPersist基本相同,唯一区别是MemoryUserDao类继承了UserDao接口,它的save()和load()方法是实现接口的方法。 这时,客户端UserRegister的代码又该如何实现呢? UserDao userDao = new MemoryUserDao(); userDao.save(user); (注:面向对象“多态”的阐述) 如果我们再切换到文本的持久化实现TextUserDao,客户端代码仍然需要手工修改。虽然我们已经使用了面向对象的多态技术,对象userDao方法的执行都是针对接口的调用,但userDao对象的创建却依赖于具体的实现类,比如上面MemoryUserDao。这样我们并没有完全实现前面所说的“Client不必知道其使用对象的具体所属类”。 如何解决客户端对象依赖具体实现类的问题呢? 下面该是我们的工厂(Factory)模式出场了!  重构第二步――工厂模式 我们使用一个工厂类来实现userDao对象的创建,这样客户端只要知道这一个工厂类就可以了,不用依赖任何具体的UserDao实现。创建userDao对象的工厂类UserDaoFactory代码如下: public class UserDaoFactory { public static UserDao createUserDao(){ return new MemoryUserDao(); } } 客户端UserRegister代码片断如下: UserDao userDao = UserDaoFactory. CreateUserDao(); userDao.save(user); 现在如果再要更换持久化方式,比如使用文本文件持久化用户信息。就算有再多的客户代码调用了用户持久化对象我们都不用担心了。因为客户端和用户持久化对象的具体实现完全解耦。我们唯一要修改的只是一个UserDaoFactory类。  重构第三步——工厂(Factory)模式的改进 到这里人生的浩劫已经得到了拯救。但我们仍不满足,因为假如将内存持久化改为文本文件持久化仍然有着硬编码的存在——UserDaoFactory类的修改。代码的修改就意味着重新编译、打包、部署甚至引入新的Bug。所以,我们不满足,因为它还不够完美! 如何才是我们心目中的完美方案?至少要消除更换持久化方式时带来的硬编码。具体实现类的可配置不正是我们需要的吗?我们在一个属性文件中配置UserDao的实现类,例如: 在属性文件中可以这样配置:userDao = com.test.MemoryUserDao。UserDao的工厂类将从这个属性文件中取得UserDao实现类的全名,再通过Class.forName(className).newInstance()语句来自动创建一个UserDao接口的具体实例。UserDaoFactory代码如下: public class UserDaoFactory { public static UserDao createUserDao(){ String className = \"\"; // ……从属性文件中取得这个UserDao的实现类全名。 UserDao userDao = null; try { userDao = (UserDao)Class.forName(className).newInstance(); } catch (Exception e) { e.printStackTrace(); } return userDao; } 通过对工厂模式的优化,我们的方案已近乎完美。如果现在要更换持久化方式,不需要再做任何的手工编码,只要修改配置文件中的userDao实现类名,将它设置为你需要更换的持久化类名即可。 我们终于可以松下一口气了?不,矛盾仍然存在。我们引入了接口,引入了工厂模式,让我们的系统高度的灵活和可配置,同时也给开发带来了一些复杂度:1、本来只有一个实现类,后来却要为这个实现类引入了一个接口。2、引入了一个接口,却还需要额外开发一个对应的工厂类。3、工厂类过多时,管理、维护非常困难。比如:当UserDao的实现类是JdbcUserDao,它使用JDBC技术来实现用户信息从持久化。也许要在取得JdbcUserDao实例时传入数据库Connection,这是仍少UserDaoFactory的硬编码。 当然,面接口编程是实现软件的可维护性和可重用行的重要原则已经勿庸置疑。这样,第一个复杂度问题是无法避免的,再说一个接口的开发和维护的工作量是微不足道的。但后面两个复杂度的问题,我们是完全可以解决的:工厂模式的终极方案——IoC模式。  重构第四步――IoC容器 使用IoC容器,用户注册类UserRegister不用主动创建UserDao实现类的实例。由IoC容器主动创建UserDao实现类的实例,并注入到用户注册类中。我们下面将使用Spring提供的IoC容器来管理我们的用户注册类。 用户注册类UserRegister的部分代码如下: public class UserRegister { private UserDao userDao = null;//由容器注入的实例对象 public void setUserDao(UserDao userDao){ this.userDao = userDao; } // UserRegister的业务方法 } 在其它的UserRegister方法中就可以直接使用userDao对象了,它的实例由Spring容器主动为它创建。但是,如何组装一个UserDao的实现类到UserRegister中呢?哦,Spring提供了配置文件来组装我们的组件。Spring的配置文件applicationContext.xml代码片断如下: DI with spring 典型的企业应用不会只由单一的对象(或bean)组成。毫无疑问,即使最简单的系统也需要多个对象一起来满足最终用户的需求。接下来的的内容除了阐述如何单独定义一系列bean外,还将描述如何让这些bean对象一起协同工作来实现一个完整的真实应用。 依赖注入(DI)背后的基本原理是对象之间的依赖关系(即一起工作的其它对象)只会通过以下几种方式来实现:构造器的参数、工厂方法的参数,或给由构造函数或者工厂方法创建的对象设置属性。因此,容器的工作就是创建bean时注入那些依赖关系。相对于由bean自己来控制其实例化、直接在构造器中指定依赖关系或则类似服务定位器(Service Locator)模式这3种自主控制依赖关系注入的方法来说,控制从根本上发生了倒转,这也正是控制反转(Inversion of Control, IoC) 名字的由来。 应用DI原则后,代码将更加清晰。而且当bean自己不再担心对象之间的依赖关系(以及在何时何地指定这种依赖关系和依赖的实际类是什么)之后,实现更高层次的松耦合将易如反掌。 DI主要有两种注入方式,即Setter注入和 构造器注入。 AOP Aop的目标是将横切性的问题以一种更加通用的方式模块化,从而提升程序的模块化程度。 定义 关注点(concern):一个关注点可以是一个特定的问题、概念、或是应用程序的兴趣区间――总而言之,应用程序必须达到的一个目标,在一个oo的应用程序中,关注点可能已经被代码模块化,也可能还散落在整个对象模型之中。 横切关注点(crosscutting concern):如果一个关注点的实现代码散落在很多个类或方法之中,我们称之为“横切关注点”。 方面(aspect):一个方面是对一个横切关注点的模块化,它将那些原本散落在各处的、用于实现这个关注点的代码规整到一处。 连接点(join point):程序执行过程中的一点,例如: 方法调用(method invocation) 字段访问(field access) 异常抛出(throws) 增强(advice):在特定连接点执行的动作。很多ao[框架都以拦截器的形式来表现增强――所谓拦截器就是当连接点被调用到时,它会收到一个回调消息。 切入点(pointcut):一组连接点的总称,用于指定某个增强应该在何时被调用。 引介(introduction):为一个现有的java类或接口添加方法或字段。 混入继承(mixin inheritance):一个“混入类”封装了一组功能,这组功能可以被“混入”到现有的类当中,并且无须求助于传统的继承手段。在aop这里,混入是通过引介来实现的。在java语言中,可以通过混入来模拟多继承。 织入(weaving):将方面整合到完整的执行流程中。 前增强(before,pre):在连接点调用之前,首先调用增强。 后增强(after,post):在连接点调用之后,再调用增强。 环绕增强(around):这类增强可以完全控制执行流程。 拦截器(interceptor):用来实现字段和方法的拦截。 Aop代理(aop proxy):即被增强的对象引用。 目标对象(target object):位于拦截器链末端的对象实例。 Aop类型 there are two distinct types of AOP: static and dynamic. The difference between them is really the point at which the weaving process occurs and how this process is achieved. Static AOP Dynamic AOP Choosing an AOP Type 实现策略 J2se动态代理(dynamic proxies):nanning 动态字节码生成(dynamic byte code generation):如CGLIB Java代码生成 使用定制的类加载器:如jboss,aspectwerkz 语言扩展:如aspectj aop设计问题 字段的拦截: 字段拦截会破坏封装,不建议使用。太多的方面:通过团队规范约束对方面的使用。 正交性:如果你需要编写应用程序专用的方面,请尽量保持它们彼此独立,并且不要依赖于执行的先后顺序。 使用aop应用程序如何测试:合理采用aop之后,单元测试就可以专注于检查业务逻辑是否实现正确,腺不必操心那些被模块化到方面中的基础设施问题。 调试:取决于aop框架。 是否严重影响性能:不会 建议:以渐进式的、实用至上的方式来使用aop. Aop最有价值的用途就是在业务方法的粒度上提供通用的企业级服务,譬如声明性事务管理和声明性安全检查等。Aop和ioc之间有特别紧密的合作关系。 spring中的aop 简介 @AspectJ支持 Schema-based AOP support AOP声明风格的选择 混合切面类型 代理机制 编程方式创建@AspectJ代理 在Spring应用中使用AspectJ Spring AOP APIs spring工作原理 框架概述 Core 封装包是框架的最基础部分,提供IoC和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。 构建于Core封装包基础上的 Context封装包,提供了一种框架式的对象访问方法,有些象JNDI注册器。Context封装包的特性得自于Beans封装包,并添加了对国际化(I18N)的支持(例如资源绑定),事件传播,资源装载的方式和Context的透明创建,比如说通过Servlet容器。 DAO 提供了JDBC的抽象层,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码。 并且,JDBC 封装包还提供了一种比编程性更好的声明性事务管理方法,不仅仅是实现了特定接口,而且对所有的POJOs(plain old Java objects)都适用。 ORM 封装包提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封装包,可以混合使用所有Spring提供的特性进行“对象/关系”映射,如前边提到的简单声明性事务管理。 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的情况,从简单的Applet一直到完整的使用Spring的事务管理功能和Web框架的企业应用。 以下是典型的完整spring web应用: 通过用Spring的 声明事务管理特性,Web应用可以做到完全事务性,就像使用EJB提供的那种容器管理的事务一样。 所有自定义的业务逻辑可以通过简单的POJO来实现,并利用Spring的IoC容器进行管理。对于其他的服务,比如发送email和不依赖web层的校验信息,还可以让你自己决定在哪里执行校验规则。 Spring本身的ORM支持可以和JPA、Hibernate、JDO以及iBatis集成起来,例如使用Hibernate,你可复用已经存在的映射文件与标准的Hibernate SessionFactory 配置。用控制器去无缝整合web层和领域模型,消除对 ActionForms 的依赖,或者避免了其他class为领域模型转换HTTP参数的需要。 使用了第三方框架的Spring中间层: 有的时候,现有情况不允许你彻底地从一种框架切换到另一种框架。然而,Spring却 不需要 强制你使用它的全部,Spring不是一种 全有全无 的解决方案。 如果,现有的应用使用了WebWork、Struts、Tapestry或其他的UI框架作为前端程序,完全可以只与Spring的事务特性进行集成。 只需要使用 ApplicationContext 来挂接你的业务逻辑和通过 WebApplicationContext 来集成你的web层前端程序。 远程使用场景: 当你需要通过WebService来访问你的现有代码时,你可使用Spring提供的 Hessian-、Burlap-、Rmi- 为前缀的接口或者 JaxRpcProxyFactory 这个代理类。你会发现,远程访问现有应用程序不再那么困难了。 EJBs-包装现有的POJOs: Spring还为EJB提供了 数据访问和抽象层,让你可以复用已存在的POJO并将他们包装在无状态SessionBean中,以便在可能需要声明式安全(EJB中的安全管理,译者注)的非安全的Web应用中使用。 Bean工厂与应用程序上下文  BeanFactory BeanFactory是Spring的“心脏”。它就是Spring IoC容器的真面目。Spring使用BeanFactory来实例化、配置和管理Bean。但是,在大多数情况我们并不直接使用BeanFactory,而是使用ApplicationContext。它也是BeanFactory的一个实现,但是它添加了一系列“框架”的特征,比如:国际化支持、资源访问、事件传播等。ApplicationContext我们将在后面章节中介绍。 BeanFactory其实是一个接口-org.springframework.beans.factory.BeanFactory,它可以配置和管理几乎所有的Java类。当然,具体的工作是由实现BeanFactory接口的实现类完成。我们最常用的BeanFactory实现是org.springframework.beans.factory.xml.XmlBeanFactory。它从XML文件中读取Bean的定义信息。当BeanFactory被创建时,Spring验证每个Bean的配置。当然,要等Bean创建之后才能设置Bean的属性。单例(Singleton)Bean在启动时就会被BeanFactory实例化,其它的Bean在请求时创建。根据BeanFactory的Java文档(Javadocs)介绍,“Bean定义的持久化方式没有任何的限制:LDAP、RDBMS、XML、属性文件,等等”。现在Spring已提供了XML文件和属性文件的实现。无疑,XML文件是定义Bean的最佳方式。 BeanFactory是初始化Bean和调用它们生命周期方法的“吃苦耐劳者”。注意,BeanFactory只能管理单例(Singleton)Bean的生命周期。它不能管理原型(prototype,非单例)Bean的生命周期。这是因为原型Bean实例被创建之后便被传给了客户端,容器失去了对它们的引用。  BeanFactory管理Bean(组件)的生命周期 下图描述了Bean的生命周期。它是由IoC容器控制。IoC容器定义Bean操作的规则,即Bean的定义(BeanDefinition)。Bean的定义包含了BeanFactory在创建Bean实例时需要的所有信息。BeanFactory首先通过构造函数创建一个Bean实例,之后它会执行Bean实例的一系列之前初始化动作,初始化结束Bean将进入准备就绪(ready)状态,这时应用程序就可以获取这些Bean实例了。最后,当你销毁单例(Singleton)Bean时,它会调用相应的销毁方法,结束Bean实例的生命周期。 (图-Bean的生命周期) 事物管理 事务是所有企业应用系统的核心。事务基础设施的目标在于让开发应用系统的程序员无需关注底层的事务处理,让数据访问对象仅包括实际的数据存取代码,而不需要编写事务处理代码。 轻量级事务基础设施 可编程的事务声明和一致的异常处理机制。 在POJO上面实现的声明式事务,无需绑定到象ejb这样的重量级组件模型上。 可插入的事务策略,以及让资源能够自动加入事务的手段。 spring事务管理 事务声明 编程式事务处理:一是在一个catch代码块中对任何异常时行回滚处理;二是通过一个IoC模板类和一个回调实现。 声明式事务处理:最适合用AOP,回事务管理有一个很明确的横切概念。 事务管理策略 持久化 数据访问策略 a.基于数据集的SQL访问(set-based SQL access) b.带有透明持久化功能的O/R映射(O/R mapping with transparent persistence) 何时选择O/R映射 一个好的O/R映射解决方案可以成功的弥合对象与关系结构之间的“阻抗不匹配”,使业务对象能够与持久化的领域对象协同工作,并且使得java开发者不必使用SQL工作。 针对领域对象的“加载/编辑/存储”流程 对象以批量查询的方式取出,但更新和删除则是单独进行 大量对象需要积极地缓存 在领域对象与数据库表/字段之间有一个相当自然的对应关系 不需要对SQL进行特别的优化 持久化数据的缓存 资源管理 连接工厂:这个工厂代表了一种特定的数据存储介质,通过它可以创建连接。连接工厂通常是一个线程安全的实例,可以从JNDI或者O/R映射产品提供的全局工厂获得。之于JDBC,扮演这个角色的是DataSource;之于JDO是PersistenceManagerFactory;之于Hibernate是SessionFactory。 连接:这个对象代表了与特定数据存储介质之间的通信会话。连接通常不是线程安全的,因此每次会话都会从连接工厂新建一个连接。之于JDBC,代表连接的是Connection对象;之于JDO是PersistenceManager;之于Hibernate是Session;之于TopLink可能是Session或UnitOfWork。 JDBC 在SQL层面上操作关系数据库,它是公认的、强大的API。主要缺点在于,如果直接使用它,需要编写很多重复的基础设施代码。 IBATIS SQL SQL语句在XML文件中定义,并预留参数占位符,在执行时,占位符将被指定的参数值所取代,参数可能来自参数映射表、javabean属性或是简单的参数对象。在执行SQL查询时,结果字段将被映射到对象,映射的方式与参数映射是一样的。 HIBERANTE 在JDBC之上提供一层薄薄的封装,同时提供完善的透明持久化;为应用程序增加O/R映射语意,但又不脱离底层关系数据库。HQL以领域对象熟悉的形式(而非数据库字段的形式)表现出来的,从而使得应用程序不必与数据库schema耦合。在很多方面,HQL都使开发者能够在领域对象的层面上充分利用SQL的强大功能。 DAO DAO模式的用途是将“与持久化相关的代码”从业务逻辑中分离出来,也就是说把业务流程和规则放在一边,与持久化相关的问题放在另一边。 数据对象和数据访问对象 DAO和透明持久化 数据访问对象的种类 DAO设计中的问题 数据访问操作的粒度 透明持久化和对象状态 事务范围和延迟加载 DAO基础设施的问题 组装 参与事务 异常处理 远程调用 分布式计算第一法则:不要分布你的对象。 RMI 作为所有java远程方案的根源,RMI(remote method invocation,远程方法调用)是在JDK1.1中引入的。它基于java的序列化机制,通信协议则是可接插的,其默认的协议是JRMP(Java remote method protocol,java远程方法协议) EJB 经典的J2EE分布式解决方案是远程 session bean。 JAX-RPC 基于WSDL的web Services:JAX-RPC Hessian 基于HTTP的轻量级远程调用协议,二进制协议 Hessian www.caucho.com/hessian Burlap 基于HTTP的轻量级远程调用协议,XML Burlap www.caucho.com/burlap Web层设计 设计目标 在一个分层体系的J2EE应用程序中,web层应可维护和扩展的:(清晰、轻薄) 1. 一个清晰的web层,将流程控制和业务对象的调用与数据的展现分开,即现在流行的MVC模式。 2. 一个瘦web层,web层应该尽可能的薄,也就是说,除了启动用户动作的业务处理以及显示结果之外,不应该再有其它的java代码。它应该只包含web专用的控制逻辑,不包含业务逻辑。 集成struts MVC对象类型 Struts对应对象 控制器 Action 拦截器 -- Command/form ActionForm 验证器 ActionForm或声明式规则 验证错误收集器 ActionErrors 模型 ActionForm或手工填入的request属性 视图引用 ActionForward 测试 测试的是一项基础的项目活动,它要有详尽的测试套件。 单元测试 是独立地测试每个类,也就是说每一个测试用例只应该测试一个类。 可测试性 1. 针对接口编程 2. 使用Strategy(策略)设计模式 3. 牢记“迪米特法则(只和他们的直接朋友对话)” 4. 尽量减少对环境相关API的依赖 5. 给每个对象一个可管理的、合理的责任集 6. 隐藏实现细节 7. 对方法进行重构,以便在测试期间覆盖某些方法 测试驱动开发 也就是测试先行开发,Test-Driven Development,TDD 覆盖率分析与其他测试工具 单元测试工具:Junit 测试生成器:Jtest www.parafoft.com 覆盖分析工具:clover www.thecortex.net 突变测试工具:jester jester.sourceforge.net 性能与可伸缩性 关注点: 1. 设置清晰的性能及吞吐量目标的重要性 2. 设计高性能J2EE应用时,最基础的架构方面的考量:是否使用EJB 3. 围绕IoC和AOP来构建系统――与EJB方案比较,哪个性能更好 4. 如何对J2EE应用进行性能调优 5. 以“循证”方式进行性能分析的重要性 定义 1. 性能 2. 吞吐量 3. 可伸缩性 设置清晰的目标 1. 吞吐量和响应时间的目标是多少? 2. 哪些操作必须很快,哪些是可以慢一些的? 3. 在什么样的硬件和软件条件下可以达到这些目标? 4. 如果需要更多的开发和维护工作量,让程序运行得更快是否值得? 5. 应用程序需要伸缩到支持多大的负荷? 6. 程序是否需要在集群环境中运行? 体系结构的选择 1. 对象分布、集群和农场 2. 数据访问 3. 其他体系结构方面的问题 不同实现的选择 1. 摆脱EJB服务设施对性能的影响 2. 缓存和代码优化 调优和部署 1. JVM 2. 应用服务器 3. 框架配置 4. 数据库配置 一种循证的性能策略 1. 基准测试 2. 采样 3. 诊断 Spring开发 最佳实践 参考 《Introduce To Spring Framework》 《J2EE Development without EJB》 《Professional Java Development with the Spring Framework》 《pro spring》 《Spring Framewo

文献:http://www.verydemo.com/demo_c143_i28595.html

你可能感兴趣的:(spring)