第14章 SpringAOP及事务支持_第1页
第14章 SpringAOP及事务支持_第2页
第14章 SpringAOP及事务支持_第3页
第14章 SpringAOP及事务支持_第4页
第14章 SpringAOP及事务支持_第5页
已阅读5页,还剩53页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、14.1 Spring的的AOP14.2 Spring的事务支持的事务支持14.1.1 代理机制代理机制关于代理机制的应用,从一个例子开始,假如有一个业务,里面有3个方法,代码如下:package xy;public class Hello public void sayHello1()System.out.println(sayHello1.);public void sayHello2()System.out.println(sayHello2.);public void sayHello3()System.out.println(sayHello3.);这个业

2、务很简单,就是输出“sayHello*.”,现在有一个需求就是在执行每一个方法之前都要验证用户是否登录,假设有一个验证方法为“validateUser()”可供我们调用,这时代码就必须修改为:package xy;public class Hello public void sayHello1()validateUser();System.out.println(sayHello1.);public void sayHello2()validateUser();System.out.println(sayHello2.);public void sayHello3(

3、)validateUser();System.out.println(sayHello3.);1静态代理静态代理【实例实例14.1】静态代理的实现。创建一个Java项目,名为StaticProxy。(1)定义接口。)定义接口。在使用静态代理时,代理对象和被代理对象实现同一接口,所以在应用代理时首先要编写一个接口:package erfaces;public interface IHello public void sayHello1();public void sayHello2();public void sayHello3();(2)编写代理类。)编写代理类。代理

4、对象和被代理对象一样实现接口IHello.java,只不过在代理对象中增加需要的服务,代理类ProxyHello.java代码如下:package xyClass;import erfaces.IHello;public class ProxyHello implements IHelloprivate IHello hello;public ProxyHello(IHello hello)this.hello=hello;public void validateUser()System.out.println(验证用户.);public v

5、oid sayHello1() validateUser();hello.sayHello1();public void sayHello2() validateUser();hello.sayHello2();public void sayHello3() validateUser();hello.sayHello3(); (3)编写被代理类。)编写被代理类。该类实现IHello接口,代码如下:package erfaces.impl;import erfaces.IHello;public class Hello implements I

6、Hellopublic void sayHello1() System.out.println(sayHello1.);public void sayHello2() System.out.println(sayHello2.);public void sayHello3() System.out.println(sayHello3.);(4)编写测试类。)编写测试类。测试类StaticTest.java,代码如下:package test;import erfaces.IHello;import erfaces.impl.Hello;imp

7、ort xyClass.ProxyHello;public class StaticTestpublic static void main(String args) /创建接口对象时应用代理类对象,并传递了被代理类对象作为构造方法的参数IHello hello=new ProxyHello(new Hello();hello.sayHello1();hello.sayHello2();hello.sayHello3();运行该测试程序,控制台信息为:验证用户.sayHello1.验证用户.sayHello2.验证用户.sayHello3.2动态代理动态代理动态代理是根

8、据静态代理的机制,抽象出一个泛类代理。它不依赖任何被代理对象的代理实现,该动态代理类需要实现InvocationHandler接口,例如,实现动态代理类DynamicProxy的代码为。调用invoke()方法会传入被代理对象的方法名与参数,也就是说,通过method.invoke(obj,objs)调用被代理类对象中的方法,返回结果也就是被代理对象中方法的返回结果。接口和接口实现类(被代理类)不变,编写测试类代码如下:package test;import erfaces.IHello;import erfaces.impl.Hello;i

9、mport xyClass.DynamicProxy;public class DynamicTest public static void main(String args)DynamicProxy proxy=new DynamicProxy();IHello hello=(IHello) proxy.bind(new Hello();hello.sayHello1();hello.sayHello2();hello.sayHello3();1横切关注点横切关注点Cross-cutting concern在介绍代理机制的例子中,验证用户方法在一个应用程序中常被安排

10、到各个处理流程之中,这些方法在AOP的术语中称为横切关注点。如图14.1所示,原来的业务流程是很单纯的,横切关注点如果直接写在负责某业务的类的流程中(如直接写到Hello.java中),使得程序的维护变得困难。另一方面,横切关注点混杂在业务逻辑之中,使得业务类本身的逻辑或程序的撰写更为复杂。为了加入日志与安全检查等服务,类的程序代码中就必须写入相关的Logging、Security等程序片段,如图14.2所示。2横切关注面横切关注面Aspect将散落在各个业务类中的横切关注点收集起来,设计为各个独立可重用的类,这种类称为横切关注面(Aspect)。对于应用程序中可重用的组件来说,以AOP的设计

11、方式,它不用知道处理提供服务的类的存在,与服务相关的API不会出现在可重用的应用组件中,因而可提高这些组件的重用性,可以将这些组件应用到其他的应用程序中,不会因为加入了某个服务而与目前的应用框架发生耦合。3连接点连接点Join point连接点是指程序中的某一个点,它分得非常细致,如对象加载、构造方法可以是连接点,一个方法、一个属性、一条语句也可以是连接点。AspectJ中的连接点主要有如下几种形式。 方法调用:方法被调用时。 方法执行:方法体的内容执行时。 构造方法调用:构造方法被调用时。 构造方法执行:构造方法体的内容执行时。 静态初始化部分执行:类中的静态部分内容初始化时。 对象预初始化

12、:主要是指执行构造方法中的this()及super()时。 对象初始化:在初始化一个类时。 属性引用:引用属性时。 属性设置:设置属性时。 异常执行:异常执行时。 通知执行:当一个AOP通知执行时。4切入点切入点Pointcuts切入点是连接点的集合,它是程序中需要注入Advice的位置的集合,指明Advice要在什么条件下被触发。5通知通知Advice通知定义了切面中的实际实现,是指在定义好的切入点处所有执行的程序代码。Spring提供3种通知(Advice)类型。 前置通知(Before Advice):指在连接点之前,先执行通知中的代码。 后置通知(After Advice):指在连接点

13、执行后,再执行通知中的代码。后置通知一般分为连接点正常返回通知及连接点异常返回通知等类型。 环绕通知(Throw Advice):环绕通知是一种功能强大的通知,可以自由地改变程序的流程、连接点返回值等。除了可以自由添加需要的横切功能外,还需要负责主动调用连接点。6拦截器拦截器Interceptor拦截器用来实现对连接点进行拦截,从而在连接点前后加入自定义的切面模块功能。在大多数Java的AOP框架中,基本上都是用拦截器来实现字段访问及方法调用的拦截。7目标对象目标对象Target object目标对象是指在基本拦截器机制实现的AOP框架中,位于拦截器链上最末端的对象实例,一般情况下,拦截器末端

14、包含的目标对象就是实际业务对象。8AOP代理代理AOP代理是指在基于拦截器机制实现的AOP框架中,实际业务对象的代理对象。Spring中的AOP代理可以使用JDK动态代理,也可以使用CGLib代理。前者为实现接口的目标对象的代理,后者为不实现接口的目标对象的代理。1前置通知前置通知Before Advice前置通知,顾名思义是在目标对象方法执行前被调用,应用前置通知需要先设计一个接口,然后编写这个接口的实现类,接着编写前置通知的逻辑代码,该代码要实现MethodBeforeAdvice接口,并覆盖其before()方法,该逻辑代码主要是编写一些需要前置的服务,最后通过配置XML文件来实现AOP

15、的前置通知。【实例实例14.2】前置通知示例。建立Java项目,命名为“Spring_AOP1”,添加Spring开发能力。(1)定义接口。)定义接口。编写接口IHello.java(该文件放入对应包下,代码第一行),代码如下:package erfaces;public interface IHello public void sayHello1();public void sayHello2();public void sayHello3();(2)接口实现类。)接口实现类。接口实现类Hello.java代码如下:package erfaces.

16、impl;import erfaces.IHello;public class Hello implements IHellopublic void sayHello1() System.out.println(sayHello1.);public void sayHello2() System.out.println(sayHello2.);public void sayHello3() System.out.println(sayHello3.);(3)实现前置通知类。本例前置通知类AdviceBeforeHello.java代码如下:package org.aop.

17、advice;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;public class AdviceBeforeHello implements MethodBeforeAdvicepublic void before(Method method, Object args, Object target)throws Throwable System.out.println(验证用户.);(4)配置前置通知。)配置前置通知。修改applicationContext.xml文件,添加

18、如下内容:erfaces.IHellobeforeAdvice(5)测试程序。)测试程序。编写测试类Test.java,代码如下:package test;import erfaces.IHello;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test public static void main(String a

19、rgs)ApplicationContext ac=new ClassPathXmlApplicationContext(applicationContext.xml);IHello hello=(IHello) ac.getBean(proxy);hello.sayHello1();hello.sayHello2();hello.sayHello3();运行该测试类,结果如下:验证用户.sayHello1.验证用户.sayHello2.验证用户.sayHello3.2后置通知后置通知After Advice后置通知与前置通知相似,不同的是在目标对象的方法执行完成后才被调用,后置通知的逻辑代码

20、类需实现AfterReturningAdvice接口,并覆盖其afterReturning()方法。【实例实例14.3】后置通知示例。后置通知类AdviceAfterHello.java代码编写如下:package org.aop.advice;import java.lang.reflect.Method;import org.springframework.aop.AfterReturningAdvice;public class AdviceAfterHello implements AfterReturningAdvicepublic void afterReturning(Objec

21、t arg0, Method arg1, Object arg2,Object arg3) throws Throwable System.out.println(方法执行完成.);修改配置文件,在上例的配置文件中添加后置通知的注册,代码修改如下:erfaces.IHelloafterAdvice代码中,加黑部分代码是添加修改的内容,可以看出,注册了后置通知Bean及在拦截器名中加入了该Bean。测试类代码不变,运行结果如下:sayHello1.方法执行完成.sayHello2.方法执行完成.sayHello3.方法执行完成.3环绕通知环绕通知Around Advice环

22、绕通知相当于前置通知和后置通知的结合使用,建立一个环绕通知类需要实现MethodInterceptor接口,并覆盖其invoke()方法。【实例实例14.4】环绕通知示例。仍以上面例子为基础,环绕通知类AdviceAroundHello.java代码如下:package org.aop.advice;import ercept.MethodInterceptor;import ercept.MethodInvocation;public class AdviceAroundHello implements Method

23、Interceptorpublic Object invoke(MethodInvocation arg0) throws Throwable System.out.println(验证用户.);Object result=null;tryresult=ceed();finallySystem.out.println(方法执行完成.);return result;修改配置文件,注册该类,代码如下: erfaces.IHellorondAdvice 可见,配置情况和前面两种相似,测试类不变,运行后在方法执行前后(环绕的)都有通知信息输出,运行结果如下:验证用

24、户.sayHello1.方法执行完成.验证用户.sayHello2.方法执行完成.验证用户.sayHello3.方法执行完成.4异常通知异常通知Throw Advice异常通知就是程序发生异常时执行相关的服务。为了造成异常发生,可以人为地抛出异常以便演示该功能。【实例实例14.5】异常通知示例。编写接口IHelloException.java,使其有异常抛出,代码如下:package erfaces;public interface IHelloException public void sayHello1() throws Throwable;public void s

25、ayHello2() throws Throwable;public void sayHello3() throws Throwable;接口实现类HelloException.java,代码如下:package erfaces.impl;import erfaces.IHelloException;public class HelloException implements IHelloExceptionpublic void sayHello1() throws Throwable System.out.println(sayHello1.);t

26、hrow new Exception(异常.);public void sayHello2() throws Throwable System.out.println(sayHello2.);throw new Exception(异常.);public void sayHello3() throws Throwable System.out.println(sayHello3.);throw new Exception(异常.);编写异常通知类,该类要实现ThrowAdvice接口,代码如下:package org.aop.advice;import org.springframework.

27、aop.ThrowsAdvice;public class AdviceThrow implements ThrowsAdvicepublic void afterThrowing(Throwable throwable)System.out.println(有异常抛出.); 修改配置文件,注册该类,代码如下: erfaces.IHelloExceptionthrowAdvice编写测试类代码:package test;import erfaces.IHelloException;import org.springframework.context.

28、ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test public static void main(String args)ApplicationContext ac=new ClassPathXmlApplicationContext(applicationContext.xml);IHelloException hello=(IHelloException) ac.getBean(proxy);tryhello.sayHe

29、llo1();hello.sayHello2();hello.sayHello3();catch(Throwable t)System.out.println(t);运行该程序,结果如下:sayHello1.有异常抛出.java.lang.Exception: 异常.5NameMatchMethodPointAdvisor下面通过修改前置通知的实例来讲解怎么应用NameMatchMethodPointAdvisor来完成仅仅对Hello.java中的“sayHello2()”方法进行前置通知,而其他方法不进行通知,这里仅修改配置文件即可,代码修改为。其他内容不变,运行测试程序,结果如下:say

30、Hello1.验证用户.sayHello2.sayHello3.6RegexpMethodPointAdvisor将上面的NameMatchMethodPointAdvisor例子用RegexpMethodPointAdvisor来完成,其他文件也不用修改,只需修改配置文件即可,代码修改为。其他的程序都不变,运行测试程序,输出结果如下:sayHello1.验证用户.sayHello2.sayHello3.1基于基于XML Schema的前置通知的前置通知通过改写Spring 1.x中的前置通知的例子来完成应用XML Scheme的前置通知。【实例实例14.6】基于XML Schema的前置通知

31、示例。首先,接口及其实现类不变,编写通知的逻辑代码AdviceBeforeHello.java,这里不用实现MethodBeforeAdvice接口,它就是一个普通的Java类,代码如下:package org.aop.advice;public class AdviceBeforeHellopublic void before()System.out.println(验证用户.);下面修改Spring的核心配置文件applicationContext.xml,代码为。该配置文件在Beans的属性中加入了schema的命名空间:xmlns:aop=http:/www.springframewo

32、/schema/aop/schema/aop/schema/aop/spring-aop-3.1.xsd接着,最重要的就是配置标签来配置一个aop片段,下面来详细讲解该片段中各标签的含义。首先来看的配置规则:下面介绍配置内容: :用来配置AOP的正则表达式,其他标签可以直接根据该标签的id属性来引用。 :用来配置AOP的切面,与pointcut相同,可以直接使用advisor的id来引用该切面。 :用来配置一个切面,ref指定要应用的通知类,用来配置通知的类型,adv

33、iceType有多种类型,可以是表示前置通知、表示后置通知、表示环绕通知、表示异常通知,pointcut-ref属性用来引用一个pointcut,method属性用来指定要应用的通知类中的方法。编写测试类Test.java,代码如下:package test;import erfaces.IHello;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public cl

34、ass Test public static void main(String args)ApplicationContext ac=new ClassPathXmlApplicationContext(applicationContext.xml);IHello hello=(IHello) ac.getBean(hello);hello.sayHello1();hello.sayHello2();hello.sayHello3();运行程序,结果如下:验证用户.sayHello1.验证用户.sayHello2.验证用户.sayHello3.2基于基于Annotation的前置通知的前置通知

35、Spring 2.x结合JDK 5及以上版本,提供了Annotation设置AOP的通知,简化了XML的配置,更加简化了AOP实现。下面将上面的例子修改为应用Annotation来配置AOP。【实例实例14.7】基于Annotation的前置通知示例。首先要修改通知类AdviceBeforeHello.java,代码修改如下:package org.aop.advice;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;Aspectpublic class AdviceBefo

36、reHelloBefore(execution(* erfaces.IHello.*(.)public void before()System.out.println(验证用户.);接下来修改XML配置文件,代码修改如下:可以看出,配置文件中仅仅加入了一句简单的“”,表示自动进行代理,Spring就会管理一切操作了。3基于基于XML Schema的后置通知的后置通知通过改写Spring 1.x中的后置通知的例子来完成应用XML Scheme的后置通知。【实例实例14.8】基于XML Schema的后置通知示例。后置通知和前置通知相似,通知类也不使用AfterReturni

37、ngAdvice接口,可以使用任意类中的任意方法作为后置通知,接口IHello.java及其实现类Hello.java不变,编写通知类代码如下:package org.aop.advice;public class AdviceAfterHellopublic void after()System.out.println(方法执行完成.);修改配置文件,代码所示。配置文件的配置方法和前置通知相似,仅仅修改了通知类型以及通知类的Bean和一些Bean的id而已。修改测试程序,加载applicationContext.xml文件,运行结果如下:sayHello1.方法执行完成.sayHello2.

38、方法执行完成.sayHello3.方法执行完成.4基于基于Annotation的后置通知的后置通知应用Annotation来标注后置通知也非常简单,大体上和基于Annotation的前置通知相似。【实例实例14.9】基于Annotation的后置通知示例。对前面程序进行修改,修改AdviceAfterHello.java代码如下:package org.aop.advice;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.Aspect;Aspectpublic class

39、AdviceAfterHelloAfterReturning(execution(* erfaces.IHello.*(.)public void after()System.out.println(方法执行完成.);配置文件也同样是加入如下一句(加黑部分代码),并删掉原定义,如下:5基于基于XML Schema的环绕通知的环绕通知同样的思路,接口IHello.java及实现类Hello.java代码不用改变,修改AdviceAroundHello.java,在环绕通知类的自定义方法中需要设置一个ProceedingJoinPoint类型的参数,环绕通知在执行完前置服务后

40、需要使用该参数来激活AOP目标对象的相关方法,然后再执行环绕通知中的后置服务。【实例实例14.10】基于XML Schema的环绕通知示例。AdviceAroundHello.java代码修改如下:package org.aop.advice;import org.aspectj.lang.ProceedingJoinPoint;public class AdviceAroundHellopublic Object around(ProceedingJoinPoint joinPoint) throws Throwable System.out.println(验证用户.);Object re

41、sult=joinPceed();System.out.println(方法执行完成.);return result;修改配置文件,代码所示。测试程序稍作修改,运行结果如下:验证用户.sayHello1.方法执行完成.验证用户.sayHello2.方法执行完成.验证用户.sayHello3.方法执行完成.6基于基于Annotation的环绕通知的环绕通知【实例实例14.11】基于Annotation的环绕通知示例。通知类AdviceAroundHello.java代码修改如下:package org.aop.advice;import org.aspectj.lang.Proc

42、eedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;Aspectpublic class AdviceAroundHelloAround(execution(* erfaces.IHello.*(.)public Object around(ProceedingJoinPoint joinPoint) throws Throwable System.out.println(验证用户.);Object result=joinPo

43、ceed();System.out.println(方法执行完成.);return result;配置文件加入如下一句(加黑部分代码),并删掉原定义,成为:7基于基于XML Schema的异常通知的异常通知【实例实例14.12】基于XML Schema的异常通知示例。接口IHelloException.java及实现类HelloException.java不变,修改异常通知类AdviceThrow.java,代码如下:package org.aop.advice;public class AdviceThrowpublic void afterThrowing()System.o

44、ut.println(有异常抛出.);修改配置文件,代码为。测试程序稍作修改,运行结果如下:有异常抛出.sayHello1.java.lang.Exception: 异常.8基于基于Annotation的异常通知的异常通知【实例实例14.13】基于Annotation的异常通知示例。异常通知类代码修改如下:package org.aop.advice;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;Aspectpublic class AdviceThrowAf

45、terThrowing(execution(* erfaces.IHellException.*(.)public void afterThrowing()System.out.println(有异常抛出.);配置文件加入如下一句(加黑部分代码),并删掉原定义,成为:Spring的事务处理是基于Spring的AOP实现的,Spring事务的中心接口是org.springframework.transaction.PlatformTransactionManager,该接口的代码为:public interface PlatformTransactionManager /获

46、得目前的事务TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;/提交事务void commit(TransactionStatus status) throws TransactionException;/事务回滚void rollback(TransactionStatus status) throws TransactionException;PlatformTransactionManager接口的第一个方法返回了一个TransactionStatus对象,可能是一个新的事务,也可能是一个已经存在的事务。如果当前执行的线程已经处于事务管理下,则返回当前线程的事务对象,否则系统将创建一个新的事务对象然后返回。TransactionStatus代表了目前的事务,该接口的代码为:public interface TransactionStatus/判断是否是一个新事务boolean isNewTransaction();/判断是否有保存点boolean hasSavepoint();/设定为只读事

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论