Spring核心技术

Ch1. Spring概述

Spring为企业应用的开发提供了一个轻量级的解决方案,包括基于依赖注入的核心机制,基于AOP的声明式事务管理,与多种持久层技术的整合,以及优秀的Web MVC框架等。Spring支持对POJOPlain Object Java Object,指最传统的Java对象,和任何模式都无关)的管理。

Spring的作者是Rod JohnsonSpring独立于应用服务器,甚至无需应用服务器的支持。

1. Spring体系介绍

l 核心机制

l Context容器

l Web支持

l MVC框架

l DAO支持

l ORM支持

l 面向方面编程支持

1.1Sping的核心和Context

Spring使用BeanFactory作为应用中负责生产和管理各组件的工厂,同时也还是组件运行的容器。BeanFactory根据配置文件确定容器中bean的实现,管理bean之间的依赖关系。ApplicationContextBeanFactory的增强,该接口提供了在J2EE应用中的大量增强功能。

1.2SpringWebMVC

SpringWeb框架围绕分发器(DispatcherServlet)设计,DispatcherServlet将请求分发到不同的处理器。SpringMVC框架提供清晰的角色划分:控制器、验证器、命令对象、表单对象和模型对象、分发器、处理器映射和视图解析器。Sping支持多种表现层技术:VelocityXSLT等等;甚至可以直接输出pdf电子文档,或者excel文档。

1.3Spring的面向方面的编程

AOP完善Spring的依赖注入(DI)。AOP提供声明式事务管理。Spring支持用户自定义切面。Spring也能和AspectJ整合。

1.4Spring的持久化支持

对各种持久化技术提供一致的编程方式。

2. Spring的基本设计思想

Spring实现了两种设计模式:工厂模式和单例模式。

例如:使用Spring至少有一个好处,即使没有PersonFactory,程序一样可以使用工厂模式,所有工厂模式的功能,Spring都可以提供。Spring对接受容器管理的bean,默认采用单体模式管理。

3. Spring的核心机制

依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色需要调用另一个角色的协助时,在传统的程序设计中,通常由调用者创建被调用者的实例。但在Spring中,创建被调用者的工作不再由调用者完成,因此称作控制反转;创建被调用者的实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。Spring的依赖注入对于调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理。依赖注入通常有两种:设值注入和构造注入。

3.1设值注入

通过setter方法来传入被调用者的实例。Spring会自动接管每个bean定义里的property元素定义。Spring会在执行无参构造函数和创建默认的bean实例后,调用对应的setter方法为程序注入属性值。Property定义的属性值将不再由该bean来主动创建、管理。而改为被动接受Spring的注入。业务对象的更换变得相当简单,对象和对象之间的依赖关系从代码里分离出来,通过配置文件动态管理。

3.2构造注入

通过构造函数完成依赖关系的设定。区别在于:创建Person实例中Axe属性的时机不同――设值注入是先创建一个默认的bean实例,然后调用对应的setter方法注入依赖关系;而构造注入则在创建bean实例时,已经完成依赖关系的注入。

注入方式

优点

设值注入

(1) 直观

(2) 对于复杂的依赖关系,如果采用构造注入,会导致构造器过于臃肿,性能下降

(3) 属性可选时,多参数的构造器更加笨重

构造注入

(1) 可在构造器中决定依赖关系的注入顺序

(2) 无需担心后续代码的破坏

(3) 更符合高内聚原则

建议采用设值注入为主,构造注入为辅的注入策略。


Ch2 Spring中的beanBeanFactory

1. Bean

1.1定义bean时,必须指定两个属性:

(1) id:确定bean的唯一标识符。

(2) class:bean的具体实现类。

1.2bean的基本行为

单例(singleton)和原型(prototype)两类。每次请求单例的bean,返回同一个对象;对于non-singleton行为的beanBeanFactory角色的行为几乎完全等于new关键字的作用,每次请求都将产生新的实例。可以通过singleton="true"来设定bean的基本行为。建议Spring中的bean应满足以下几个原则:

1)每个bean的实现类都应该提供无参数的构造函数。

2)接受构造注入的bean,则应提供对应的构造函数。

3)接受设值注入的bean,则应提供对应的setter方法,并不强制提供对应的getter方法。

1.3 实例化bean

3种方法:

1)调用构造函数“new”一个实例。

2BeanFactory调用某个类的静态工厂方法创建bean

主要有以下变化:

l class元素不再是bean的实现类,而是静态工厂类。

l 必须有factory-method属性确定产生实例的静态工厂方法。

l 静态工厂方法需要参数,则使用<constructor-arg>元素确定静态工厂方法。

(3) BeanFactory调用实例工厂方法创建bean

采用实例工厂方法创建bean不能含有class元素,应指定如下两个属性:

l 工厂beanid,该id属性应该对应Spring容器中的一个工厂bean

l 工厂方法名,该方法可以产生bean实例。

与调用静态工厂方法的区别:

l 实例工厂方法,必须将实例工厂配置成bean实例;调用静态工厂方法,无需配置工厂bean

l 实例工厂方法,必须使用factory-bean属性确定工厂bean;而静态工厂方法创建bean,则使用class元素确定静态工厂类。

1.4 bean特性的深入

BeanFactoryApplicationContext初始化容器中bean的时机不同,前者等到程序需要bean实例的时候才创建bean;后者等到加载ApplicationContext实例时,会自动创建容器中的全部beanBean的依赖通常可以接受如下元素指定值:

l value

l ref:对属性值是其他bean的情况,推荐采用ref,而不是valueref的两个属性:bean用于确定不在同一个XML配置文件中的bean;而local用于确定在同一个XML配置文件中其他bean,并且local属性只能是其他beanid属性。

l bean:定义嵌套bean实例属性,而不是Spring中已经存在的bean,没有id属性。损失了灵活性,提高了内聚性。

l listsetmap以及props:分别用于设置类型为ListSetMapPropertis的属性值。

1.4.1 使用depends-on强制初始化bean

1.4.2 自动装配

自动装配减少了配置文件的工作量,但降低了依赖关系的透明性和清晰性。设置bean元素的autowire属性,指定自动装配,可取值如下:nobyNamebyTypeconstructorautodetect。对于大型的应用,不鼓励使用自动装配,不利于高层次解耦。

1.4.3 依赖检查

默认是不使用依赖检查,通过bean元素的dependency-check属性来设置依赖检查,该属性有以下的值:nonesimpleobjectall

1.5 Bean的生命周期

1.5.1 协调不同步的bean

singleton bean依赖于non-singleton bean时,singleton bean只有一次初始化机会,依赖关系的设置也在初始化时进行,会产生不同步现象。解决办法是利用方法注入。要保证lookup方法注入每次产生新的bean实例,必须将目标bean部署成non-singleton。否则,由于容器中只有一个bean实例,即使采用lookup方法注入,每次依然返回同一个bean实例。Lookup方法注入不仅用于设值注入,也可以用于构造注入。

1.5.2 定制bean的生命周期行为

管理bean的生命周期行为主要为如下两个时机:

l bean的全部依赖注入之后。Spring提供2种方式在bean的全部属性设置之后执行特定的行为:使用init-method;实现InitializingBean接口。

l bean即将被销毁之前。Spring提供2种方式在bean销毁之前执行特定的行为:使用destroy-method;实现DisposableBean接口。

1 使用init-method的例子

程序的运行结果如下:

spring实例化依赖beansteelaxe实例...

spring初始化主调beanchinese实例...

spring执行依赖关系注入...

正在执行初始化方法...

2)实现接口InitializingBean或者DisposableBean污染了代码,是侵入式设计,因此不推荐使用。

Ch3 bean的高级功能

Bean的管理,是Spring的核心部分。

3.1 bean的继承

bean定义可以从父bean定义继承部分配置。它也可以覆盖一些配置,或者添加一些配置。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>3.1.1</span></chsdate> 抽象bean

bean不需要实例化,它只是作为子bean定义的模板使用,而ApplicationContext默认初始化所有的singleton bean,可以使用abstract=”true”来阻止初始化父bean。抽象bean是一个bean模板,容器会忽略所有抽象bean定义,也不会实例化抽象bean,所以抽象bean可以没有class属性。并且只要企图初始化抽象bean,都将导致错误。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>3.1.2</span></chsdate> 定义子bean

bean可以从父bean继承实现类、构造器参数、属性值,也可增加新的值。如果指定init-methoddestroy-methodfactory-method属性,则它们会覆盖父bean的定义。

bean无法从父bean继承如下属性:depends-onautowiredependency-checksingletonlazy-init。在子bean中指定parent属性即可。对于class属性,父子bean中必须指定一个,如果子bean中指定了class属性,则将覆盖父bean中的属性。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>3.1.3</span></chsdate> Spring中的bean的继承和java中的继承的区别

前者只是实例和实例之间的参数的延续,是对象和对象之间的关系。而后者则是类和类之间的关系。

Spring中的bean继承

Java中的继承

类型

bean和父bean可以是不同的类型

子类是一种特殊的父类

表现

实例之间的关系,表现为参数值的延续

类之间的关系,表现为方法、属性的延续

多态

bean不可作为父bean使用,不具备多态性

子类实例可以作为父类实例使用

3.2高级依赖注入

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>3.2.1</span></chsdate> 属性值的依赖注入

通过PropertyPathFactoryBean来完成的。必须指定如下2个属性:

(1)targetBeanName:用于指定目标bean,确定获取哪个bean的属性值。(2)propertyPath:用于指定属性,确定获取目标bean的哪个属性值。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>3.2.2</span></chsdate> field值的依赖注入

通过FieldRetrievingFactoryBean来完成的,用来获取目标beanfield值。获得的值可以注入其他bean,也可以直接定义成新的bean

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>3.2.3</span></chsdate> 方法返回值的依赖注入

通过MethodInvokingFactoryBean来完成的,用来获得某个方法的返回值,该方法既可以是静态方法,也可以是实例方法。获得的值可以注入其他bean,也可以直接定义成新的bean。使用实例方法返回值,必须指定如下2个属性:

1targetObject:确定目标bean,该bean既可以是容器中已有的bean,也可以是嵌套bean

2targetMethod:确定目标方法,通过确定目标bean的哪个方法返回值注入。

使用静态方法返回值,必须指定如下2个属性:

1targetClass:确定目标class

2targetMethod:确定目标方法,通过确定目标bean的哪个方法返回值注入。

3.3 使用BeanPostProcessor

如果有更多的方法,需要在被创建时被调用,可使用BeanPostProcessor接口。

3.4 使用BeanFactoryPostProcessor

如果需要beanBeanFactory实例化之后,对BeanFactory进行某些处理,可让该bean实现BeanFactoryPostProcessor接口。

实现BeanFactoryPostProcessor接口的bean能对BeanFactory执行处理,这种bean称其为容器后处理器。Spring提供许多容器后处理器,包括:

1PropertyPlaceHolderConfigurer:属性占位符配置器。

2PropertyOverrideConfigurer:另一种属性占位符配置器。

如果PropertyOverrideConfigurer属性文件中有对应配置信息,XML文件中的配置信息被覆盖;否则直接使用XML文件中的配置信息。

3BeanNameAutoProxyCreator:自动生成代理的辅助类。

3.5 与容器交互

Spring容器本质上是一个高级“工厂”,负责产生bean的实例。容器通常有2种表现形式:

l BeanFactory

l ApplicationContext

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>3.5.1</span></chsdate> 工厂bean简介与配置

工厂bean的配置没有什么不同,区别在于产品bean的配置。产品bean不需要提供class元素配置产品bean通常有如下2种方法:

l 使用factory-method属性确定工厂方法

l bean方法返回值定义成bean实例

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>3.5.2</span></chsdate> 使用FactoryBean接口

可简化工厂bean的开发。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>3.5.3</span></chsdate> 使用BeanFactoryAware获取BeanFactory

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>3.5.4</span></chsdate> 使用BeanNameAware回调本身

3.6 ApplicationContext介绍

Context的基础是ApplicationContext接口,它继承BeanFactory接口,提供BeanFactory所有的功能。为了以一种更面向框架的方式工作,context包使用分层和有继承关系的上下文,包括:

l MessageSource,提供国际化支持。

l 资源访问,比如URL和文件。

l 事件传递。

l 载入多个配置文件。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"'>3.6.1</span></chsdate> 国际化支持

MessageSource Bean的名字必须是messageSource。通常采用Spring的实现类ResourceBundleMessageSource

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"'>3.6.2</span></chsdate> 事件处理

是通过ApplicationEvent类和ApplicationListener接口来实现的。如果容器中有一个ApplicationListener bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener bean将自动响应,这是标准的观察者模式Spring提供如下3个内置事件:

l ContextClosedEvent

l ContextRefreshedEvent

l RequestHandledEvent

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt'>3.6.3</span></chsdate> web应用中自动加载ApplicationContext

可通过ContextLoader声明式的创建ApplicationContextContextLoader有两个实现类:

l ContextLoaderListener

l ContextLoaderServlet

web.xml中添加如下:

<context-param>

<param-name>

contextConfigLocation

</param-name>

<param-value>

/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml

</param-value>

</context-param>

<Listener>

<Listener-class>

org.springframework.web.context.ContextLoaderListener

<Listener-class>

</Listener>

<servlet>

<servlet-name>context</servlet-name>

<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

应将context的启动级别设成最小,即最优先启动。

3.7 汇总多个XML配置文件

每个配置文件仅仅配置功能近似的bean,多个配置文件最终的汇总的方式如下:

l 使用ApplicationContext加载多个配置文件;FileSystemXmlApplicationContextClassPathXmlApplicationContext的区别在于:前者从当前目录搜索配置文件;而后者从classpath路径搜索配置文件。

l Web应用启动时加载多个配置文件;通过ContextLoaderListener可以加载多个配置文件。

l XML配置文件中导入其他配置。元素import可用于导入其他配置文件。


Ch4 Spring中的资源访问

传统的资源访问通常采用java.net.URL和文件IO,操作复杂,对于某些特定的资源,例如访问ServletContext下的某个文件,没有提供专门的APISpring则通过Resource接口完成,对资源访问提供了更多的包装。

4.1 传统资源访问和Spring的资源访问

1. 传统资源访问

java.net.URL的构造函数如下:

URL(Stringprotocol, Stringhost, intport, Stringfile, URLStreamHandlerhandler)
Creates a URL object from the specified protocol, host, port number, file, and handler.

2. Spring中的资源访问

Resource直接可以作为资源访问的工具类使用。

Interface Resource

Interface for a resource descriptor that abstracts from the actual type of underlying resource, such as a file or class path resource.

4.2 Resource实现类

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>4.2.1</span></chsdate> 访问网络资源

UrlResource类实现。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>4.2.2</span></chsdate> 使用ClassPathResource

加载在classpath路径里搜索到的资源。自动搜索位于WEB-INF/classes下的资源文件,无需使用绝对路径。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>4.2.3</span></chsdate> 访问文件系统资源

通过FileSystemResource访问本地文件系统。与前面的2种访问资源的区别在于:资源字符串确定的资源位于本地文件系统内,而且无需前缀。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>4.2.4</span></chsdate> 访问应用相关资源

访问web context相对路径的资源,采用ServletContextResource类。通过java.io.File访问要求资源解压缩,而且在本地文件系统内;而使用ServletContextResource则无需关心资源是否被解压,总可通过servlet容器访问。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"'>4.2.5</span></chsdate> 访问输入流资源

只有没有合适的Resource实现时,才考虑使用InputStreamResource。通常情况下,优先考虑ByteArrayResource,或者FileSystemResource实现。InputStreamResource是一个被打开的Resource,如果需要多次读取某个流,就不要使用InputStreamResource

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"'>4.2.6</span></chsdate> 访问字节数组资源

通过ByteArrayResource来实现对字节数组资源的访问。实际应用中,字节数组可能通过网络传输获得,也可能通过管道流获得。

4.3 ResourceLoader接口和ResourceLoaderAware接口

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-hansi-font-family: Arial'>4.3.1</span></chsdate> 使用ResourceLoader

实现类可以返回一个Resource类实例。常见前缀:

l classpath:从classpath加载资源,创建classpath实例。

l fle:以UrlResource实例访问本地文件系统的资源。

l http:以UrlResource实例访问web服务的资源

l 无前缀:取决于ApplicationContext的实现。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"'>4.3.2</span></chsdate> 使用ResourceLoaderAware

部署在容器中的ResourceLoaderAware能够获得容器的引用。

4.4 使用Resource作为属性

如果bean需要访问资源,2种办法:

l 代码中创建Resource实例,资源的位置固定在代码中,不好。

l 使用依赖注入,允许动态配置资源的位置。甚至可以指定资源的访问策略,在配置文件中使用特定前缀,就可使用特定的Resource实现。

4.5 ApplicationContext中使用资源

确定资源访问策略通常有以下2个办法:

l ApplicationContext实现类来确定访问策略,通过前缀指定资源访问策略,仅对当次有效,以后还是根据ApplicationContext实现类来确定的。建议显示采用对应的实现类。

l 前缀确定访问策略。Classpath*、“beans*.xml”。


Ch5 表现层数据的处理

类型转换和数据校验是表现层数据处理的两个任务。

5.1表现层数据的处理

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>5.1.1</span></chsdate> 类型转换

<group id="_x0000_s1026" style="WIDTH: 414pt; HEIGHT: 101.4pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line" editas="canvas" coordorigin="1800,2848" coordsize="8280,2028"><lock v:ext="edit" aspectratio="t"></lock><shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_s1027" style="LEFT: 1800px; WIDTH: 8280px; POSITION: absolute; TOP: 2848px; HEIGHT: 2028px" o:preferrelative="f" type="#_x0000_t75"><font size="2"><fill o:detectmouseclick="t"></fill><path o:extrusionok="t" o:connecttype="none"></path><lock v:ext="edit" text="t"></lock></font></shape><group id="_x0000_s1028" style="LEFT: 2520px; WIDTH: 6300px; POSITION: absolute; TOP: 3160px; HEIGHT: 1560px" coordorigin="2520,3160" coordsize="6300,1560"><group id="_x0000_s1029" style="LEFT: 2520px; WIDTH: 6300px; POSITION: absolute; TOP: 3161px; HEIGHT: 1559px" coordorigin="2520,3161" coordsize="6300,1559"><rect id="_x0000_s1030" style="LEFT: 2520px; WIDTH: 1620px; POSITION: absolute; TOP: 4253px; HEIGHT: 467px"><textbox><table cellspacing="0" cellpadding="0" width="100%"><tbody><tr> <td style="BORDER-LEFT-COLOR: #ece9d8; BORDER-BOTTOM-COLOR: #ece9d8; BORDER-TOP-COLOR: #ece9d8; BACKGROUND-COLOR: transparent; BORDER-RIGHT-COLOR: #ece9d8"> <div> <p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><font face="Courier New" size="2">多种数据类型</font></span></p> </div> </td> </tr></tbody></table></textbox></rect><rect id="_x0000_s1031" style="LEFT: 7380px; WIDTH: 1440px; POSITION: absolute; TOP: 4253px; HEIGHT: 467px"><textbox><table cellspacing="0" cellpadding="0" width="100%"><tbody><tr> <td style="BORDER-LEFT-COLOR: #ece9d8; BORDER-BOTTOM-COLOR: #ece9d8; BORDER-TOP-COLOR: #ece9d8; BACKGROUND-COLOR: transparent; BORDER-RIGHT-COLOR: #ece9d8"> <div> <p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><font face="Courier New" size="2">字符串类型</font></span></p> </div> </td> </tr></tbody></table></textbox></rect><line id="_x0000_s1032" style="POSITION: absolute" to="7380,4410" from="4140,4409"><stroke endarrow="block"><font size="2"></font></stroke></line><line id="_x0000_s1033" style="POSITION: absolute; flip: x" to="7380,4565" from="4140,4564"><stroke endarrow="block"><font size="2"></font></stroke></line><shapetype id="_x0000_t61" coordsize="21600,21600" o:spt="61" path="m,l0@8@12@24,0@9,,21600@6,21600@15@27@7,21600,21600,21600,21600@9@18@30,21600@8,21600,0@7,0@21@33@6,xe" adj="1350,25920"><stroke joinstyle="miter"></stroke><formulas><f eqn="sum 10800 0 #0"></f><f eqn="sum 10800 0 #1"></f><f eqn="sum #0 0 #1"></f><f eqn="sum @0 @1 0"></f><f eqn="sum 21600 0 #0"></f><f eqn="sum 21600 0 #1"></f><f eqn="if @0 3600 12600"></f><f eqn="if @0 9000 18000"></f><f eqn="if @1 3600 12600"></f><f eqn="if @1 9000 18000"></f><f eqn="if @2 0 #0"></f><f eqn="if @3 @10 0"></f><f eqn="if #0 0 @11"></f><f eqn="if @2 @6 #0"></f><f eqn="if @3 @6 @13"></f><f eqn="if @5 @6 @14"></f><f eqn="if @2 #0 21600"></f><f eqn="if @3 21600 @16"></f><f eqn="if @4 21600 @17"></f><f eqn="if @2 #0 @6"></f><f eqn="if @3 @19 @6"></f><f eqn="if #1 @6 @20"></f><f eqn="if @2 @8 #1"></f><f eqn="if @3 @22 @8"></f><f eqn="if #0 @8 @23"></f><f eqn="if @2 21600 #1"></f><f eqn="if @3 21600 @25"></f><f eqn="if @5 21600 @26"></f><f eqn="if @2 #1 @8"></f><f eqn="if @3 @8 @28"></f><f eqn="if @4 @8 @29"></f><f eqn="if @2 #1 0"></f><f eqn="if @3 @31 0"></f><f eqn="if #1 0 @32"></f><f eqn="val #0"></f><f eqn="val #1"></f></formulas><path o:connecttype="custom" o:connectlocs="10800,0;0,10800;10800,21600;21600,10800;@34,@35"></path><handles><h position="#0,#1"></h></handles></shapetype><shape id="_x0000_s1034" style="LEFT: 7380px; WIDTH: 541px; POSITION: absolute; TOP: 3161px; HEIGHT: 803px" type="#_x0000_t61" adj="-56895,33274"><textbox><table cellspacing="0" cellpadding="0" width="100%"><tbody><tr> <td style="BORDER-LEFT-COLOR: #ece9d8; BORDER-BOTTOM-COLOR: #ece9d8; BORDER-TOP-COLOR: #ece9d8; BACKGROUND-COLOR: transparent; BORDER-RIGHT-COLOR: #ece9d8"> <div> <p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><font face="Courier New"><font size="2"><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">输入</span><span lang="EN-US" style="FONT-SIZE: 9pt"><p></p></span></font></font></p> </div> </td> </tr></tbody></table></textbox></shape></group><shape id="_x0000_s1035" style="LEFT: 3600px; WIDTH: 540px; POSITION: absolute; TOP: 3160px; HEIGHT: 780px" type="#_x0000_t61" adj="87600,38548"><textbox><table cellspacing="0" cellpadding="0" width="100%"><tbody><tr> <td style="BORDER-LEFT-COLOR: #ece9d8; BORDER-BOTTOM-COLOR: #ece9d8; BORDER-TOP-COLOR: #ece9d8; BACKGROUND-COLOR: transparent; BORDER-RIGHT-COLOR: #ece9d8"> <div> <p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><font face="Courier New" size="2">输出</font></span></p> </div> </td> </tr></tbody></table></textbox></shape></group><wrap type="none"></wrap><anchorlock></anchorlock></group>

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>5.1.2</span></chsdate> 数据校验

1. 客户端校验

通常采用JavaScript完成。

2. 服务器端校验

5.2 Spring支持的表现层数据处理

Spring提供web mvc框架实现,提供:

l 数据绑定,通过spring:bind标签完成。

l Bean包装,bean包装的核心是BeanWrapper接口,程序中并不直接使用BeanWrapper,而使用DataBinderBeanFactory,这两个类加强了BeanWrapper的功能。

l 数据校验,通过ValidatorErrors类完成。

web mvc中,数据绑定和数据校验几乎同时完成。

5.3 bean包装

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-bidi-font-size: 10.5pt'>5.3.1</span></chsdate> 获取修改bean属性

BeanWrapper接口的方法:

l setPropertyValue(StringpropertyName, Objectvalue) 或者setPropertyValue(PropertyValuepv)

l getPropertyValue(StringpropertyName)

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"'>5.3.2</span></chsdate> 类型转换

使用PropertyEditor自动完成类型转换。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"'>5.3.3</span></chsdate> 内建的PropertyEditor

ByteArrayPropertyEditorClassEditorCustomBooleanEditorCustomCollectionEditorCustomDateEditorCustomNumberEditorFileEditorInputStreamEditorLocaleEditorPropertiesEditorStringTrimmerEditorURIEditor等等。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"; mso-hansi-font-family: Arial'>5.3.4</span></chsdate> 自定义PropertyEditor

继承java.beans.PropertyEditorSupport,重写setAsText(Stringtext)方法。

5.4 数据校验

通过ValidatorErrors类完成,校验时,Validator将校验错误发送给Errors队象。具体的校验可用ValidationUtils完成。


Ch6 SpringAOP的支持

AOP不会取代OOP,而是作为OOP的补充。AOP从动态的角度考虑程序结构,提取业务处理过程的切面。AOP框架具有以下2个特征:

l 各个步骤之间的良好隔离性。

l 源代码无关性。

6.1 AOP入门

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"'>6.1.1</span></chsdate> 概念

l 切面:关注点的模块化,关注点可能横切多个对象。

l 连接点:程序运行过程中明确的点,如方法的调用,或者异常的抛出。Spring AOP中,连接点总是方法的调用,Spring并没有显式的使用连接点。

l 处理:AOP框架在特定的连接点执行的动作。处理包括“around”、“before”、“throws”等类型。大部分框架都以拦截器作为处理模型。

l 切入点:系列连接点的集合,它确定处理触发的时机。AOP框架允许开发者自己定义切入点:例如使用正则表达式。

l 引入:添加方法或者字段到被处理的类。Spring允许引入新的接口到任何被处理的对象。例如:可以使用一个引入,使任何对象实现IsModified接口,以此来简化缓存。

l 目标对象:包含连接点的对象;也称为被处理对象,或者被代理对象。

l AOP代理:AOP框架创建的对象,包含处理。Spring中的AOP代理可以是JDK动态代理,也可以是CGLIB代理。前者为实现接口的目标对象的代理,后者为不实现接口的目标对象的代理。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"'>6.1.2</span></chsdate><span lang="EN-US" style='FONT-FAMILY: "Courier New"'> A</span></chsdate>OP代理

AOP代理提供比目标对象更加强大的功能。目标对象是蓝本,AOP代理是目标对象的加强,在目标代理的基础上,增加了属性和方法,提供更加强大的功能。Spring对接口实现类采用Dynamic Proxy实现AOP,而对没有实现任何接口的类,则通过CGLIB实现AOP代理。

6.2 SpringAOP的支持

如果处理非常细粒度的对象,AspectJ是更适合的选择。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><span lang="EN-US" style='FONT-FAMILY: "Courier New"'>6.2.1</span></chsdate> Spring的切入点

org.springframework.aop.Pointcut是切入点的抽象。

1)正则表达式切入点

org.springframework.aop.support.Perl5RegexpMethodPointcutSpring的正则表达式切入点。org.springframework.aop.support. JdkRegexpMethodPointcut(默认使用)则是另一种正则表达式切入点。

2)自定义切入点

通常继承静态切入点的实现类StaticMethodMatcherPointcut。当然也有动态切入点的超类。

3Spring的处理

同一个处理,可以处理多个目标对象,这种处理称为per-class处理,也可以每个目标对象都有自己的处理,这种处理称为per-instance处理。Spring中的实用处理类型有5种:

l Around处理,需要实现MethodInterceptor接口。

l Before处理,不需要MethodInvocation对象,要实现MethodBeforeAdvice接口。

l Throws处理,当连接点抛出异常时,Throws处理被调用。实现Throws异常,必须实现ThrowsAdvice接口。

l After Returning处理,和Before非常相似。必须实现AfterReturningAdvice接口。

l Introduction处理,一种特殊的拦截处理,不能作用于任何切入点。因为它总是作用于类层次,而不是方法层次。需要实现IntroductionAdvisorIntroductionInterceptor接口。

Aspect Oriented Programming”,“面向方面编程”还是“面向切面编程”?目标方法中含有一些共有的过程,将这些过程抽取出来,提高程序的复用性。提取出来的共有操作是必不可少的,必须还原给目标方法:方法是最小的封装体――无法修改!此时,程序需要一个切入点,在此处将共有操作还原到目标方法。这个过程由AOP框架完成,其中共有操作就是处理(Advice)。在上述过程中,切入点不能在方法体内,而被确定在方法调用之前,方法调用之后,或者异常抛出之时。AOP框架负责将共有操作在合适的时机(切入点),还愿给目标方法,生成代理。

4Advisor

Advisor等于切入点加上处理。Advisoraspect的模块化表示。DefaultPointcutAdvisor是最普通的Advisor类。Spring可在一个AOP代理中混合使用Advisor和处理,将自动创建必要的拦截器。

6.3 创建AOP代理

org.springframework.aop.framework.ProxyFactoryBean是生成代理的基本途径。配置ProxyFactoryBean时需要确定以下属性:

l 代理的目标

l 是否使用CGLIB

1)代理类

如果目标类没有实现接口,需要对类生成代理,而不能为接口生成代理。需使用CGLIBCGLIB代理在运行期间产生目标对象的子类,该子类通过装饰器模式加入到Advice中。因为CGLIB是目标对象类,则需考虑:

l 目标类不能声明为final,因为final类不能被继承无法生成代理;

l 目标方法也不能声明为finalfinal方法不能被重写,无法得到处理。

6.4 实用的代理工厂类

不如ProxyFactoryBean全面,但是简单、实用。例如:

l org.springframework.transaction.interceptor.TransactionProxyFactoryBean

l org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean,用于创建EJB代理,通过EJB代理,客户端代码无需进行JNDI查找,也无需使用EJBcreate方法。为了使AOP能生成代理,提供另一个普通接口,该接口无需继承任何特殊的类,但接管EJB业务接口中的全部方法。

6.5 简介的代理定义方式

利用父子bean的继承关系来简化代理的定义。

6.6 自动代理

通过BeanPostProcessor实现,常用的两个实现类,是aop.framework.autoproxy包中的BeanNameAutoProxyCreatorDefaultAdvisorAutoProxyCreator。通过自动代理,可以:

l 避免每个目标bean定义代理;

l 避免客户端代码调用目标bean

6.7 编程式创建AOP代理

通过org.springframework.aop.framework.ProxyFactory完成。通常,不要将AOP配置信息放在java代码中。

6.8 操作代理

无论怎样创建AOP代理,这些AOP代理都将实现Advised接口。

Ch7 Spring的事务管理

Spring之前,没有一个比较好的事务管理策略,既能极好的把代码从特定事务API中解耦,又可消除大段的事务管理代码,同时还能跨越多个事务资源。

7.1 使用PlatformTransactionManager接口

7.2 编程式事务

Spring提供如下两种编程式的事务管理

l 使用TransactionTemplate管理事务;推荐采用。

l 直接使用一个PlatformTransactionManager实现类管理事务,类似于JTA,但没有异常处理。

7.3 声明式事务

通过AOP实现。

结论:尽可能使用声明式事务。

参考:《Spring 2.0 宝典》 李刚 编著

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值