Top Banner
Spring 简简简简简
132

Spring框架

Nov 02, 2014

Download

Technology

eastsky

Spring框架 概述
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Spring框架

Spring简介与入门

Page 2: Spring框架

Spring简介 与 Hibernate 、 Struts 一样, Spring 也是一个开源项

目,它的作者是 Rod Johnson ,官方网站是 http://www.springframework.org/ 。

Spring 的基础思想来源于 Rod Johnson 的一本著名的j2ee 书籍: Expert One-on-One J2EE Design and Development 。在这本书中, Rod Johnson 列举 EJB的种种问题,并提出了相应的解决办法。

从那时起,人们对于 EJB 的狂热追捧才算结束,转而进入更理性的时代。

Page 3: Spring框架

Spring简介 Rod Johnson 是悉尼大学博士, 猜猜他的专业是什么? Rod Johnson 在开发出 Spring

 之前,主要从事项目开发咨询 与培训工作。在 Spring 被广泛认可之后,创办

了 interface21 公司,致力于 Spring 咨询与培训 Rod Johnson 还是 JDO2.0 和 Servlet2.4 专家

组成员。

Page 4: Spring框架

Spring简介 Spring 核心技术包括两个方面,一是控制反转

( Inversion of Control, IoC ),另一个是面向方面编程( Aspect Oriented Programming, AOP )。

Spring 囊括了十分丰富的内容,包括表述层、数据层,它提供了许多原来只有 EJB 才能提供的功能(如宣称式的事务管理),但 Spring 又无须运行在 EJB 容器上。

无论 Spring 涉足到哪一个领域,使用的都是简单的JavaBean ,一般无须再实现复杂的接口。

Page 5: Spring框架

Spring简介

Page 6: Spring框架

Spring简介

Page 7: Spring框架

Spring技术基础 Spring 的核心是 IoC 和 AOP ,它们都是由 Java 原有

技术发展而来的。 IoC 技术是通过 Java 的反射机制以及 JavaBean 的自

省机制实现的 AOP 技术是依赖代理模式实现的, JFC 中提供了对

代理模式的内在支持, Spring 也是通过这种技术实现的。

为了能够理解 Spring 的 IoC 机制,下面对反射机制和自省机制做简单介绍。

Page 8: Spring框架

反射机制 Java 的反射机制允许程序在运行时动态加载对象,并

且动态地调用其中的方法。 JFC 中的 java.lang.reflect 包便提供了这种支持,主

要是通过 java.lang.Class 、 java.lang.reflect.Method 、Field 、 Constuctor 等类完成这项工作的。

例如,如果有下面的方法:Object myInvoke(String class, String methodName, Objec[] args)实现动态调用某一类的某一方法,该如何实现?

Page 9: Spring框架

反射机制public Object myInvoke(String className, String methodName, Object args[]) {

Object results = null;try {

Class clazz = Class.forName(className);Method method = null;for (int i = 0; i < clazz.getMethods().length; i++) {

method = clazz.getMethods()[i];if(methodName.equals(method.getName())) {

results = method.invoke(clazz.newInstance(), args);break;

}}

} catch (Exception e) {e.printStackTrace();

}return results;

}

Page 10: Spring框架

反射机制 使用时指明类名和方法名:class SomeToBeInvoke {

public int calculate(int i) {return i*i;

}}

ReflectDemo demo = new ReflectDemo();Object obj = demo.myInvoke("SomeToBeInvoke",

"calculate", new Object[]{new Integer(6)});System.out.println(obj);

Page 11: Spring框架

Class类 java.lang.Class 代表一个类,可以通过三种方

式得到 Class 的实例:1. Object.getClass()2. Class.forName()3. 直接用类名点 class ,如: A.class Class 的实例代表的是类,不代表类的实例。

即 Class c = A.class , c 是类而不是实例。如果创建实例,可以调用 newInstance() 方法。

Page 12: Spring框架

Class类 可以通过 Class 加载类并了解类的内部结构:1. 获取构造函数:

Constructor getConstructor(Class[] parameterTypes) Constructor[] getConstructors()

2. 获取方法: Method getMethod(String name, Class[] parameterTypes)Method[] getMethods()

3. 获取属性:Field getField(String name) Field[] getFields()

4. 检查特性: Class[] getInterfaces() 、 Package getPackage() 、 boolean isArray() 、 boolean isInterface()

Page 13: Spring框架

Field类 java.lang.reflect.Field 代表属性,是

java.lang.reflect.AccessibleObject 的子类,故可以调用其 setAccessible 方法访问 private类型的属性。

Field 中声明了多个 getter 和 setter 方法,可以设置属性的值。

Page 14: Spring框架

Method类 java.lang.reflect.Method 代表类中的方法,

它也是 java.lang.reflect.AccessibleObject的子类,可以通过 setAccessible 访问 private类型方法。

可以通过调用 Object invoke(Object obj, Object[] args) 方法,间接调用对象方法。

Page 15: Spring框架

Contructor类 java.lang.reflect.Constructor 代表构造函数,

是 java.lang.reflect.AccessibleObject 的子类,可以通过 setAccessible 访问 private 类型方法。

可以通过 Object newInstance(Object[] initargs 方法调用构造函数,创建新实例。

Page 16: Spring框架

JavaBean自省机制 JavaBean 的属性一般都具有 getter 方法和

setter 方法,通过这些方法可以更改或读取JavaBean 属性。

JavaBean具有的自省机制可以在不知道JavaBean 都有哪些属性的情况下,设置它们的值。

Page 17: Spring框架

Introspector

自省机制是使用 Introspector 实现的。 Introspector 的方法大部分都是静态的,可以直接调

用,如 getBeanInfo(Class beanClass) 可以得到一个 JavaBean 的 BeanInfo 实例。

BeanInfo 实例包含了一个 JavaBean 类属性和方法的信息。如:

1. BeanDescriptor getBeanDescriptor()2. MethodDescriptor[] getMethodDescriptors() 3. PropertyDescriptor[] getPropertyDescriptors()

Page 18: Spring框架

PropertyDescriptor

PropertyDescriptor 代表了属性,可以通过它得到属性的 getter 方法和 setter 方法。即 :

1. Method getReadMethod()2. Method getWriteMethod() 通常在不知道 JavaBean 属性时,如果设置

JavaBean 属性就采用 PropertyDescriptor 。PropertyDescriptor(String propertyName, Class beanClass)

Page 19: Spring框架

所谓代理模式即是由代理对象接管对象访问,用户在使用时感觉是在原始对象操作,但实际是通过代理对象访问的原始对象。

Java 为代理模式提供了内置的支持,这是通过 java.lang.reflect.Proxy 以及java.lang.reflect. InvocationHandler 实现的。

代理( Proxy)模式

Page 20: Spring框架

代理( Proxy)模式所谓代理,就是一个人或者一个机构代表另一

个人或者另一个机构采取行动。 在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

Page 21: Spring框架

代理模式的结构

Page 22: Spring框架

代理模式的角色 抽象主题角色:声明了真实主题和代理主题的共同接

口,这样在任何可用真实主题的地方都可以使用代理主题。

代理主题角色:代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象,代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作。

真实主题角色:定义了代理角色所代表的真实对象。

Page 23: Spring框架

代理模式的时序

Page 24: Spring框架

装配 Bean

Page 25: Spring框架

IoC 与 Bean装配 在 Spring 中,对象间的协作是通过 IoC 机制完成的。 反向控制也叫依赖注入( Dependency Injection , D

I ),简单来说就是将 JavaBean需要的对象通过配置文件加载进来。

Spring 提供了两种装配 Bean 的容器,一是BeanFactoy ,另一个是 ApplicationContext 。

两者做为容器,所有的 Bean 都应该通过容器装配,而容器也知道自己都装配了哪些 Bean 。

Page 26: Spring框架

Bean容器 ApplicationContext 与 BeanFactory 都是接

口, ApplicationContext 是由 BeanFactory 接口扩展而来,它增强了 BeanFactory 的功能。

Bean 容器能够加载的对象并不一定是严格遵循JavaBeans规范的 Java 类,任何可实例化的类都可以通过 Spring Bean 容器加载进来。通常称这些类为POJO 。

要记住, BeanFactory 不仅仅只具备实例化 Bean 的功能,它还知道所有的 Bean ,可以配置和管理它们。

Page 27: Spring框架

BeanFactory

以下是 BeanFactory 声明的方法,都是与 Bean装配相关的:

boolean containsBean(String name)

String[] getAliases(String name)

Object getBean(String name)

Object getBean(String name, Class requiredType)

Class getType(String name)

boolean isSingleton(String name)

Page 28: Spring框架

BeanFactory Spring给出一些 BeanFactory 的实现类,其中最为常用的是

XmlBeanFactory 。1 、通过文件系统Resource res = new FileSystemResource("beans.xml");XmlBeanFactory factory = new XmlBeanFactory(res);2 、通过类路径ClassPathResource res = new ClassPathResource("beans.xml");XmlBeanFactory factory = new XmlBeanFactory(res);3 、通过 ApplicationContext 加载ClassPathXmlApplicationContext appContext = new

ClassPathXmlApplicationContext(new String[] {"applicationContext.xml", "applicationContext-part2.xml"});BeanFactory factory = (BeanFactory) appContext;

Page 29: Spring框架

Resource

创建 XmlBeanFactory 时需要以 Resource 作为构造函数的参数。

Resource 接口位于org.springframework.core.io 包内,通过XmlBeanFactory 创建 BeanFactory 时都要使用到这个接口。

Resource 代表了所有可以访问的底层资源,如文件系统、类路径、 URL 等等。

Page 30: Spring框架

Resource 实现了 Resource 接口的类包括:1. AbstractResource, 2. ByteArrayResource, -- byte[]3. ClassPathResource, -- String path4. DescriptiveResource, -- String description 不实际

指向资源,只包含描述信息5. FileSystemResource, -- File , or, String path6. InputStreamResource, -- InputStream7. ServletContextResource, -- ServletContext, String8. UrlResource -- URL , or , String path

Page 31: Spring框架

Resource

Resource 中定义了以下方法:1. Resource createRelative(String relativePath)

2. boolean exists()

3. String getDescription()

4. File getFile()

5. String getFilename()

6. URL getURL()

7. boolean isOpen()

Page 32: Spring框架

装配 Bean

通常可以通过三种方式装配 Bean

1. 通过 setter 方法2. 通过构造函数3. 自动装配 其中,使用 setter 方法装配 Bean 是最为常

用的。

Page 33: Spring框架

装配 Bean

无论使用 BeanFactory 还是 Applicationcontext均可以视之为容器,使用的 Bean必须向容器注册。

注册是通过在配置文件中加入 Bean 声明:<beans> <bean id=“first” class=“mybeans.FirstBean”/> <bean id=“second" class=“mybeans.Second”/></beans> 注册后的 Bean 是被容器识别的,容器可以协调他们

之间的关系

Page 34: Spring框架

装配 Bean

<!ELEMENT bean (

description?,

(constructor-arg |

property |

lookup-method |

replaced-method)*

)>

Page 35: Spring框架

原型或单例 如下代码的执行结果是什么?FirstBean bean = (FirstBean)factory.getBean("my");

FirstBean bean1 = (FirstBean)factory.getBean("my");

System.out.println(bean==bean1); 结果依赖于 bean元素的 singleton 属性,如果设置

true ,则以单例模式加载 bean ,则永远指向同一个bean;反之则每次实例化一个。

也即在单例模式下, BeanFactory维护所有的 bean

Page 36: Spring框架

原型或单例 BeanFactory维护所有单例 bean ,也即维护

了对单例 bean 的引用,因此 factory 只知道创建单例 bean 的数目,而无从知晓原型 bean 。

原型 bean 创建后即脱离了容器,容器不维护对 bean 的引用,因此也无法再管理 bean 。

不是绝对必要,不要使用原型,而应尽可能使用单例。

Page 37: Spring框架

延迟加载 如下代码执行的结果是什么?System.out.println("before loading");FirstBean bean = (FirstBean)factory.getBean("my");System.out.println(“after loading”);在 bean 的构造函数中,包含:System.out.println(“bean init”); 结果依赖于 bean 的 lazy-init 属性,如果设置为 true ,则在第一次加载该 bean 时初始化;否则在初始化容器时就加载所有 bean 。

延迟加载仅在 bean 单例模式下起作用。

Page 38: Spring框架

初始化与清理 在许多情况下,需要在对象加载后立即初始化资源,而在删除对象前先清理资源

在 spring 中,提供了两种方式实现初始化和清理工作。

通过设置 bean 的 init-method 和 destroy-method 指定初始与清理方法

通过实现 InitializingBean 及 DisposableBean接口,由容器在加载与删除 bean 时自动调用。

Page 39: Spring框架

初始化与清理<bean id="first" class="mybeans.FirstBean" init-

method="init" destroy-method="destroy" > <property name="message"> <value>Hi, Rod Johnson</value> </property></bean> 可以通过 destroySingletons 方法删除所有单例 bean 原型 bean 在创建后即脱离 BeanFactory 的维护,所

以只能调用初始化方法,而不能做清理工作。

Page 40: Spring框架

初始化与清理 通过 InitializingBean 和 DisposableBean. InitializingBean 接口中仅定义了一个方法,即

void afterPropertiesSet() DisposableBean 接口也是这样,方法为: 

void destroy() 这两个接口都位于

org.springframework.beans.factory 包中,须向容器注册 id 以及 class 。

Page 41: Spring框架

初始化与清理 初始化与清理的次序1. 无论是哪种初始化方式,都是在 bean 构造

完毕,并且属性已经注入到对象中后才执行的。

2. 初始化时, InitializingBean定义的初始化方法先于 init-method 中指定的方法。

3. 清理时, DisposableBean定义的清理方法先于 destroy-method 指定的方法。

Page 42: Spring框架

Setter装配 在配置文件中, <bean>元素的 <property>元素指明了使用属

性的 setter 方法注入依赖。<!ELEMENT property (

description?,(bean | ref | idref | value | null | list | set | map | props)?

)>

<!ATTLIST property name CDATA #REQUIRED><!ATTLIST property ref CDATA #IMPLIED><!ATTLIST property value CDATA #IMPLIED> Setter装配要求 bean 中必须与相应的 setter 方法,即使没有这

个属性

Page 43: Spring框架

Setter装配-装配种类 可以通过 setter 方法加载以下类型的属性:1. 基本类型2. Bean 类型3. 内部 bean 类型4. 集合类型5. 设置空值

Page 44: Spring框架

Setter装配-基本类型 装配基本类型:1. 包括八种基本类型及它们的包装类,还有

String 类型。2. 不必关心具体类型, spring 可以通过反射机

制了解到属性的类型信息3. 可以通过 <property> 的子元素 <value> 来设

置基本类型的值,也可以通过其属性 value来设置,效果完全相同。

Page 45: Spring框架

Setter装配-基本类型<bean id="first" class="mybeans.FirstBean" >

<property name="message">

<value>Hi, Rod Johnson</value>

</property>

<property name="age" value="1" />

</bean>注意不能同时使用 value 子元素和 value 属性

Page 46: Spring框架

Setter装配- bean类型 装配 bean 类型属性:1. 只有通过配置文件向容器注册的 bean 才能

通过注入机制设置到其它 bean 的属性上。2. 使用 <ref> 子元素或 ref 属性设置3. Spring即是通过这种方式建立起 bean间的

依赖关系,实现强大的 bean 管理功能。

Page 47: Spring框架

Setter装配- bean类型 <bean id="first" class="mybeans.FirstBean"> <property name="message"> <value>Hi, Rod Johnson</value> </property> <property name="age" value="1" /> <property name="second" ref="second"/> </bean> <bean id=“second” class=“mybeans.SecondBean” > <property name="first"> <ref bean="first"/> </property> </bean>

Page 48: Spring框架

Setter装配- bean类型 内部 Bean<bean id="outer" class="...">

<property name="target"><bean class="com.mycompany.PersonImpl">

<property name="name"><value>Tony</value>

</property></bean>

</property></bean>

Page 49: Spring框架

Setter装配-集合类型 Spring 支持以下四种集合的装配:1. <list>-- java.util.List

2. <set>-- java.util.Set

3. <map>-- java.util.Map

4. <props>-- java.util.Properties

Page 50: Spring框架

Setter装配- list集合<property name="someList">

<list><value>someValue</value><ref bean="myDataSource"/><list>

<value>anyValue</value></list>

</list></property>

Page 51: Spring框架

Setter装配- set集合<property name="someSet">

<set>

<value>just some string</value>

<ref bean="myDataSource"/>

</set>

</property>

Page 52: Spring框架

Setter装配-map集合<property name="someMap">

<map><entry>

<key><value>yup an entry</value></key><value>just some string</value>

</entry><entry>

<key><value>yup a ref</value></key><ref bean="myDataSource"/>

</entry></map>

</property>

Page 53: Spring框架

Setter装配- props集合<property name="people">

<props><prop key="HarryPotter">

The magic property</prop><prop key="JerrySeinfeld">

The funny property</prop>

</props></property>

Page 54: Spring框架

Setter装配-设置 null 如果希望将属性设置为空,使用以下方法不能达到目

的:<property name="age" > <value></value></property> 应该按如下方式注入:<property name="age" > <null/></property> 属性必须为 Object

Page 55: Spring框架

构造装配 构造装配通过构造函数装配 bean 属性,一

般在以下情况下使用:1. 属性没有 setter 方法,是只读属性2. 属性只需要设置一次,以后就不会再更改3. 一般使用构造装配只装配少量属性 构造装配下,构造函数中应该包含有需要装配的属性

Page 56: Spring框架

构造装配<bean id="first" class="mybeans.FirstBean"> <constructor-arg> <value>http://www.sohu.com</value> </constructor-arg> <constructor-arg> <value>http://localhost:8080</value> </constructor-arg> <property name="age" value="1" /></bean> 多个参数时使用多个 constructor-arg 指定,出现次序决定了参

数次序,或者使用 index 属性指定

Page 57: Spring框架

自动装配 可以通过 spring框架自动为 bean装配属性。 自动装配只能装配 bean 类型,即取代 ref元素。

使用自动装配只需在 bean元素中加入属性autowire ,自动装配可被手动装配覆盖。

也可以选择在 beans 中加入 default-autowire属性,为所有 bean 设置默认自动装配。

Page 58: Spring框架

自动装配类型 “no“-不使用自动装配, spring推荐。 “byName”-依据名称或 ID装配 bean ,如果没有找

到,则不装配 “byType”-依据类型自动装配,如果存在两个以上同

种类型,则抛出异常。 “constructor”-依据当前 bean 构造函数装配,查找

与构造函数参数同类型 bean “autodetect”-自动检测,先通过 constructor ,再使

用 byType

Page 59: Spring框架

装配 Bean

通过 BeanFactory 获取 Bean 与直接 new 一个 Bean 是完全不同的。

通过 BeanFactory 获取的 bean 能将所有依赖注入到 bean 中,属性的值会依设置而定。

New 出来的 bean 属性值必须主动设置。 在需要使用 spring框架情况下,所有 bean 都

应该由容器来管理。

Page 60: Spring框架

ApplicationContext ApplicationContext 与 BeanFactory 的作用相类似,都起到装配、管理

Bean 的作用。 不同的是, ApplicationContext 在此基础上增强了 BeanFactory 的功能,

这包括国际化、加载资源、发布事件等等。 实现了 ApplicationContext 接口的类包括:1 、 ClassPathXmlApplicationContext2 、 FileSystemXmlApplicationContext3 、 GenericApplicationContext4 、 GenericWebApplicationContext5 、 StaticApplicationContext6 、 StaticWebApplicationContext7 、 XmlWebApplicationContext 它们的使用方法与 BeanFactory 基本相同

Page 61: Spring框架

ApplicationContext

ApplicationContext 接口由以下接口扩展而来: ListableBeanFactory-可以列出所有 bean HierarchicalBeanFactory-可以找到父工厂 MessageSource-处理国际化 ApplicationEventPublisher-处理事件 ResourcePatternResolver-资源解析

Page 62: Spring框架

面向切面- AOP

Page 63: Spring框架

AOP简介 AOP最初由 Gregor Kiczales

在施乐的 Palo Alto研究中心领导的一个研究小组于 1997年提出。

目前,宣称能够支持 AOP 的项目已达近百种, Java语言的实现也有 20 多种,其中最为完善的是 AspectJ 。这是由Gregor Kiczales 领导的小组完成的。

Page 64: Spring框架

AOP简介 AOP 是 OOP 的延续,是 Aspect Oriented

Programming 的缩写,意思是面向方面编程。 它将分布在各个类中具有相同功能的代码片段整合到一起,由单独的功能模块完成,不仅减少了代码的重复量,降低了耦合,也提高了代码的可维护性。

不要认为 AOP会取代 OOP ,它只是 OOP 的补充。但就像当年的 OOP 一样,它很可能引发一场软件产业的革命。

Page 65: Spring框架

AOP简介

Page 66: Spring框架

AOP术语切面( Aspect ):从对象中抽取出来的交叉

功能模块通知( Adivice ):切面的具体实现

连接点( Joinpoint ):可以插入方法的地方切入点( Pointcut ):连接点的集合

引入( Introduction ):为已经存在的类添加新方法和属性

Page 67: Spring框架

AOP术语 目标对象( Target Object ):

被通知的对象 代理( AOP Proxy ):

由 AOP框架创建的目标对象的代理对象织入( Weaving ):将通知与目标对象结合在一起,生成新的代码片段的过程

Page 68: Spring框架

AOP实现技术 目前,人们使用传统语言对核心业务进行编程,对横切

面的功能模块则使用面向切面的编程语言。 面向切面的编程语言可以是已有编程语言的扩展,如

AspectJ , AspectC++ , AspectC , AspectC# , Apostle 等,或是一种新的语言

Java语言可以使用反射( Reflection ),基于动态代理( Dynamic Proxy )或其它机制的拦截框架,基于元数据( Metadata )的操作,以及类载入时对字节码的操作等来实现 AOP 。

Page 69: Spring框架

AOP实现技术 Spring 使用两种机制实现 AOP 技术,一是使

用 java 的动态代理,即java.lang.reflect.Proxy 类创建代理。

二是使用 CGLIB库自动生成目标对象的子类,同时织入通知。

动态代理要求目标对象必须要实现接口(只有这样才能创建代理),而 CGLIB则没有这种限制。

Page 70: Spring框架

AOP实现技术 由于目前 AOP 还没有完全的统一标准,因此

实现出来的 AOP框架也是多种多样的,为此人们成立了一个 AOP联盟,用于统一这种混乱局面

Aop Alliance 是由多个 AOP 项目组成的组织,定义一套 AOP标准的 Java 接口,以方便各种AOP框架可以互通。

Spring 也是以这套接口为基础的。

Page 71: Spring框架

AOP快速入门 背景:课程在开课前应该向任课老师发出上课通知。

创建步骤:1. 创建目标对象,目标对象必须是实现了某种

接口的。2. 创建通知,通知定义了一个切面的具体逻辑。3. 向上下文注册。

Page 72: Spring框架

AOP快速入门-创建目标public class J2eeCourse implements Course {

String name;public J2eeCourse(String name) {

this.name = name;}public void process(Teacher teacher) {

System.out.println(name + " is in process, and the teacher is “ + teacher.getName());

teacher.giveClass();}

public String getName() {return name;

}}

Page 73: Spring框架

AOP快速入门-创建目标 使用 Java 动态代理机制实现的 AOP必须要将

目标对象中的方法声明在一个接口中:public interface Course {

public void process(Teacher teacher);

public String getName();

}

Page 74: Spring框架

AOP快速入门-创建通知此处创建的是前置通知:public class CourseAdvice implements MethodBeforeAdvice {

public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {

Course course = (Course)arg2;Teacher teacher = (Teacher) arg1[0];System.out.println("hi, teacher " + teacher.getName() +

", there is a " + course.getName()+", do you have time to listener this class?");

}

}

Page 75: Spring框架

AOP快速入门-注册<beans> <bean id="courseTarget" class="aop.J2eeCourse"> <constructor-arg value=” j2ee“/> </bean> <bean id="rod" class="aop.TeacherRod"> <constructor-arg value=“Rod Johnson”/> </bean> <bean id="advice" class="aop.CourseAdvice"/> <bean id="course" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value=“aop.Course”/> <property name="interceptorNames"> <list><value>advice</value></list> </property> <property name="target” ref"courseTarget" /> </bean></beans>

Page 76: Spring框架

通知的类型 通知是切面的具体实现,在 Spring 中通知被

分为以下几种类型:

Page 77: Spring框架

通知的类型 除 MethodInterceptor (环绕通知)是由 aop

alliance定义以外,其余接口均位于org.springframework.aop 中

MethodInterceptor位于org.aopalliance.intercept 包中,因此如果需要使用这个接口,必须导入 aopalliance 的 jar文件。

Page 78: Spring框架

切入点切入点用于定义通知加入到目标对象中的位置,没有切入点通知将被应用于所有方法上。

Spring 以 org.springframework.aop.PointCut来定义切入点。

切入点分为两类,即静态切入点和动态切入点静态切入点下,通知总被执行,动态切入点下,

通知依据运行时的参数决定通知是否需要执行。

Page 79: Spring框架

切入点

Page 80: Spring框架

Advisor概述 由于 ProxyFactoryBean 只接受 Advice 和

Advisor 类型的 Interceptor (参照 API ),所以不能直接应用 PointCut 到 ProxyFactoryBean 上

Advisor 是 Spring AOP 中特有的概念,它持有通知,并决定通知是否应用到当前实例上。

由于切入点是决定通知是否应用的重要依据,故PointcutAdvisor 中持有通知和切入点,并依据切入点决定是否应用通知。

Page 81: Spring框架

Advisor概述public interface Advisor {

Advice getAdvice();      boolean isPerInstance();

}

public interface PointcutAdvisor extends Advisor {Pointcut getPointcut()

}由于 PointcutAdvisor继承自 Advisor ,因此可以当成Interceptor 使用。

Page 82: Spring框架

内置切入点 静态切入点1. StaticMethodMatcherPointcut(抽象)2. NameMatchMethodPointcut-名字匹配3. JdkRegexpMethodPointcut - JDK 与此同时表达式4. Perl5RegexpMethodPointcut - Perl 5正则表达式 动态切入点1. DynamicMethodMatcherPointcut (抽象)2. ControlFlowPointcut

Page 83: Spring框架

名称匹配 在 NameMatchMethodPointcut 中,除了定义了一般 PointCut 的方法外,还定义了以下一些方法:

1. void setMappedName(String mappedName)

2. void setMappedNames(String[] mappedNames)

只有与指定名称匹配的方法才会被应用通知,可以通过 IOC 机制设置匹配名称。

Page 84: Spring框架

相应 Advisor

与 NameMatchMethodPointcut 对应的Advisor 是NameMatchMethodPointcutAdvisor。

在 NameMatchMethodPointcutAdvisor 中没有定义直接设置 PointCut 的方法,但由于是由 NameMatchMethodPointcutAdvisor继承而来,故可以通过设置 mappedName生成。

Page 85: Spring框架

相应 Advisor<bean id="advice" class="aop.CourseAdvice"/><bean id="advisor"

class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name=“mappedName” value=”process“/> <property name=“advice” ref="advice"/></bean><bean id="course"

class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces“ value=“aop.Course”/> <property name="interceptorNames"> <list><value>advisor</value></list> </property> <property name="target“ ref="courseTarget" /></bean>在定义mappedName 时,可以使用通配符 *

Page 86: Spring框架

正则表达式匹配 通过直接指定方法的办法简单有效,但如果在

大型系统中,方法较多的情况下,一个个指出通知的方法名则会显得臃肿。

JdkRegexpMethodPointcut 使用正则表达式的形式指定匹配的方法,是更为通用的一种方法。

除了 JdkRegexpMethodPointcut 还有Perl5RegexpMethodPointcut ,它们的区别仅在于前者使用 JDK语法,而后者使用 perl 5

Page 87: Spring框架

正则表达式匹配 无论是 JDK版本的,还是 Perl5版本的,它

们都是由 AbstractRegexpMethodPointcut继承而来,这个方法中定义以下两个方法:

1. void setPattern(String pattern) 2. void setPatterns(String[] patterns) 可以使用 IOC 机制定义正则表达式。 特别强调,正则表达式下,匹配的是类名和

方法名

Page 88: Spring框架

相应 Advisor

与这两个 PointCut 对应的 Advisor 都是RegexpMethodPointcutAdvisor

1. Pointcut getPointcut()

2. void setPattern(String pattern)

3. void setPatterns(String[] patterns)

4. void setPerl5(boolean perl5) 设置 setPerl5 为 true 时,强制使用 Perl 5语法形式

的正则表达式,这时必须引入 Jakarta ORO 包

Page 89: Spring框架

相应 Advisor

<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

<property name="pattern"> <value.*process.*</value> </property> <property name="advice"> <ref bean="advice"/> </property></bean>标红处写成 ^aop\.Course\.process$ 只针对一个类的一个特定方法

Page 90: Spring框架

数据层应用

Page 91: Spring框架

DAO支持 Spring 提供了对数据层的广泛支持,这包括:1. 传统 JDBC2. Hibernate3. JDO4. Oracle TopLink5. Apache OJB6. iBATIS SQL Map

Page 92: Spring框架

JDBC方式 Spring JDBC 方式采用模板与回调相结合的模

式,核心类是 JdbcTemplate 。

Page 93: Spring框架

JDBC方式 使用 JDBC 方法处理 DAO ,必须要知道数

据源 DataSource 。 Spring DAO 层中,获取数据源方法有三种:1. 通过 JNDI

2. 使用第三方的连接池3. 使用 DriverManagerDataSource

Page 94: Spring框架

DriverManagerDataSource

为了方便测试, Spring 提供了简便易用的DataSource 实现,即 DriverManagerDataSource ,可直接创建 :

DriverManagerDataSource dataSource = new DriverManagerDataSource();

dataSource.setDriverClassName( “……");

dataSource.setUrl( “……");

dataSource.setUsername( “……");

dataSource.setPassword( “……");

Page 95: Spring框架

DriverManagerDataSource

也可以通过 IOC 机制注入:<bean id="dataSource"

class="org.springframework.jdbc.datasource.DriverManagerDataSource">

<property name="driverClassName" value="com.mysql.jdbc.Driver"/>

<property name="url" value="jdbc:mysql://localhost:3306/hibernate"/>

<property name="username" value="root"/> <property name="password" value="root"/></bean>

Page 96: Spring框架

第三方连接池最常使用的第三方连接池是 Apache 的 jakarta

common dbcp 项目。这里主要使用的是org.apache.commons.dbcp.BasicDataSource

由于 BasicDataSource 的属性均通过 setter方法暴露出来,因此可以使用 IOC 机制注入。

例如:

Page 97: Spring框架

第三方连接池 <bean id="newDs"

class="org.apache.commons.dbcp.BasicDataSource">

<property name="driverClassName" value="com.mysql.jdbc.Driver" />

<property name="url" value="jdbc:mysql://localhost:3306/hibernate" />

<property name="username" value="root" /> <property name="password" value="root" /> </bean>

Page 98: Spring框架

JNDI方式<bean id="dataSource"

class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"

value="java:comp/env/jdbc/DataSource"/> </bean> <bean id="jt"

class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/></bean> 注意, JdbcTemplate 中的 dataSource 是 DataSource 类型,但

设置的却是 JndiObjectFactoryBean 。

Page 99: Spring框架

JdbcTemplate

总的来说, Spring 在支持 JDBC 访问数据库时采用了模板与回调相结合的方式。其中:

1. JdbcTemplate 是模板;2. StatementCallback 是执行 Statement语句的回调;3. PreparedStatementCallback 、 PreparedStatemen

tCreator 、 PreparedStatementSetter 是PreparedStatement语句的回调

4. CallableStatementCallback 等是CallableStatement语句的回调。

Page 100: Spring框架

JdbcTemplate查询 依据模板回调原则, Spring定义了以下查询方法:1. Object query(PreparedStatementCreator psc,

ResultSetExtractor rse)

2. List query(PreparedStatementCreator psc, RowCallbackHandler rch)

3. List query(PreparedStatementCreator psc, RowMapper rowMapper)

以上几个方法中,第一个参数用于生成语句,第二个参数则用于处理结果,它们都用于在运行时回调

Page 101: Spring框架

JdbcTemplate查询 Spring 提供了一些简便的查询方法:1. temp.queryForList("select * from building");返回 List ,内部元素为 Map ,键对象为列名,值对象为列值。

2. temp.queryForMap("select * from building where id=3");返回Map ,键对象为列名,值对象为列值,所以要求必须返回单一行。

3. temp.queryForObject("select building_name from building where id=1", String.class)返回对象,依据指定的类型决定返回对象的类型,仅针对单行单列

4. 此外还有 queryForInt 及 queryForLong 等等。

Page 102: Spring框架

JdbcTemplate更新 依据模板回调原则, Spring定义了以下更新

方法:1. int update(PreparedStatementCreator psc) 2. int update(PreparedStatementCreator psc,

KeyHolder generatedKeyHolder) 3. int update(PreparedStatementCreator psc,

PreparedStatementSetter pss) 以上参数也均为方法提供了运行回调接口。

Page 103: Spring框架

JdbcTemplate更新 为了方便, Spring同样定义更新使用的方法:1. int update(String sql)

2. int update(String sql, Object[] args)

3. int update(String sql, Object[] args, int[] argTypes)

4. int update(String sql, PreparedStatementSetter pss)

用法参照 API

Page 104: Spring框架

映射对象 Spring 同 Hibernate 类似,也可以将查询结果映射成对象,但这需要用户自定义。

这是通过 SqlQuery 和 SqlUpdate 类实现的,前者用于查询,后者用于更新。 SqlQuery 是抽象类,一般使用其子类 MappingSqlQuery类派生子类。

Page 105: Spring框架

映射对象

Page 106: Spring框架

映射对象

Page 107: Spring框架

整合 Hibernate

Hibernate 的核心是 SessionFactory ,它就像 JDBC中的 DataSource 一样。

Spring 提供了以 IOC 机制导入 SessionFactory 的可能,这是通过 LocalSessionFactoryBean 实现的。

由于 Hibernate版本更新向前不兼容,因此 Spring 也提供了两套接口对于不同的 Hibernate版本。

org.springframework.orm.hibernate 支持 Hibernate 2.1 ,而 org.springframework.orm.hibernate3 则支持hibernate3

Page 108: Spring框架

整合 Hibernate

Page 109: Spring框架

整合 Hibernate

在应用上, Spring 也提供了模板与回调模式来实现 Hibernate 对数据库的操作。

HibernateTemplate 是模板,而HibernateCallback则是回调接口。

HibernateTemplate 提供的 execute 方法,需要以 HibernateCallback 为参数,执行时则在合适的时候回调对象。

Page 110: Spring框架

整合 Hibernate

类似于 JdbcTemplate , HiberateTemplate 中也加入了一些简便的方法,可以实现增、删改操作。

这些方法基本都可以在 Hibernate 的 Session接口中找到,或者是 HQL 、 QBC 、 QBE 等等。

具体参照 API文档

Page 111: Spring框架

表述层应用

Page 112: Spring框架

集成 Struts

Spring 提供了三种集成 Struts 的方法:1. 显式集成2. Action 代理3. RequestProcessor 代理 无论是哪种方法都必须先向 Struts框架注册一个插件,即:

Page 113: Spring框架

显式集成 显示集成 Struts 时要求所有需要使用 Spring

的 Action 都必须通过显式继承ActionSupport ,位于org.springframework.web.struts. 包中

这个类是 Action 的子类,包含了能够得到ApplicationContext 的方法,即

1. WebApplicationContext getWebApplicationContext()

Page 114: Spring框架

Action代理 Action 代理方式集成 Struts需要将所有 Action

的地址都映射到 DelegatingActionProxy 上,位于 org.springframework.web.struts 包中。

它也是 Action 的子类,代理所有 Action请求。真正的 Action请求则以 Spring注册 bean 的形式注册在容器中,如:

Page 115: Spring框架

Action代理

多模块时,路径如何写?

Page 116: Spring框架

RequestProcessor代理 RequestProcessor 代理的方式是改写了模块

控制器,要求模块控制器必须是DelegatingRequestProcessor 。

这时,所有的 Action 都会被转到 Spring 中查找,所以在 Struts 中配置 action 的 type 属性已经没有意义:

Page 117: Spring框架

Spring事务支持 Spring最为自豪的当属事务管理,因为它在不

使用 EJB服务器的情况下,实现了对事务的宣称式支持。这在以往是仅能由 Session Bean 提供的功能。

Spring 对事务的宣称式支持是通过 AOP 机制实现,也即在需要声明事务属性的方法中织入通知。

Page 118: Spring框架

Spring事务支持

Page 119: Spring框架

Spring事务支持

注:以上类均实现了 PlatformTransactionManager

Page 120: Spring框架

Spring事务支持 由于不同的平台实现事务管理采用的是不同的资源,例如 JDBC 使用直接使用 Connection管理事务,而 Hibernate则使用 Session 。

在实现上, Spring 要求为 JDBC 事务管理器注入数据源 DataSource ,而为 Hibernate 事务管理器注入 SessionFactory

所以使用不同的数据层解决方案,相应的事务管理器也完全不同。

Page 121: Spring框架

Spring事务支持

Page 122: Spring框架

Spring事务支持 与 EJB 相同, Spring 对事务的支持也分为编

程式和宣称式两种(对应 EJB 的 BMT 和CMT )。

在编程式事务管理中, Spring 依然采用了模板与回调模式。

在宣称式事务管理中, Spring采用了与 EJB类似的事务属性来管理事务。

Page 123: Spring框架

编程式事务管理 Spring 提供了两种方式实现编程式事务管理:1 、使用 TransactionTemplate 与

TransactionCallback 结合。2 、直接使用一个 PlatformTransactionManager

的实现。

Page 124: Spring框架

编程式事务管理 使用 TransactionTemplate 时,在其内部仍然

要知道具体的事务管理平台,即PlatformTransactionManager 。这可以通过IOC 机制注入。如

Page 125: Spring框架

编程式事务管理

Page 126: Spring框架

编程式事务管理 事实上, Spring 为模板提供了两个回调类,

即 TransactionCallbackWithoutResult 和TransactionCallback ,前者是后者的实现,并且是一个抽象类。

TransactionStatus 作为参数传给回调函数,通过 TransactionStatus 可以设置事务只可回滚。

需要注意,运行时异常可导致自动回滚。其余则必须设置成只可回滚。

Page 127: Spring框架

编程式事务管理 也可直接使用 PlatformTransactionManager :

Page 128: Spring框架

宣称式事务 Spring 宣称式事务与 Session Bean 的 CMT 事务管

理在使用上极为相似,但是在很多方面 Spring 要优于 EJB :

1. EJB 事务管理是绑定在 JTA 上的,而 Spring则可以应用在任何情况下。

2. EJB 事务管理不支持 POJOs3. Spring 提供声明式回滚规则,并且可以通过 AOP 在

事务中定制其它行为4. Spring 不依赖服务器 但有一点, Spring 是无法取代 EJB 的,那就是分布

式的事务管理。

Page 129: Spring框架

宣称式事务 Spring 的宣称式事务管理实际上是应用了

Spring 的 AOP 特性,将事务管理的代码织入到原代码中。

使用的代理类是TransactionProxyFactoryBean ,位于org.springframework.transaction.interceptor包

Page 130: Spring框架

宣称式事务

Page 131: Spring框架

传播行为

Page 132: Spring框架

传播行为