第15章++Spring的AOP及事务支持.ppt_第1页
第15章++Spring的AOP及事务支持.ppt_第2页
第15章++Spring的AOP及事务支持.ppt_第3页
第15章++Spring的AOP及事务支持.ppt_第4页
第15章++Spring的AOP及事务支持.ppt_第5页
已阅读5页,还剩54页未读 继续免费阅读

下载本文档

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

文档简介

第15章Spring的AOP及事务支持,15.1Spring的AOP,15.2Spring的事务支持,15.1Spring的AOP,15.1.1代理机制关于代理机制的应用我们从一个例子开始,假如有一个业务,里面有3种方法,代码如下:xy;publicclassHellopublicvoidsayHello1()System.out.println(sayHello1.);publicvoidsayHello2()System.out.println(sayHello2.);publicvoidsayHello3()System.out.println(sayHello3.);,15.1.1代理机制,这个业务很简单,就是输出“sayHello*.”,现在有一个需求就是在执行每一个方法之前都要验证用户是否登录,假设有一个验证方法为“validateUser()”可供我们调用,这时代码就必须修改为:xy;publicclassHellopublicvoidsayHello1()validateUser();System.out.println(sayHello1.);publicvoidsayHello2()validateUser();System.out.println(sayHello2.);publicvoidsayHello3()validateUser();System.out.println(sayHello3.);,15.1.1代理机制,1静态代理在使用静态代理时,代理对象和被代理对象实现同一接口,所以在应用代理时首先要编写一个接口:erfaces;publicinterfaceIHellopublicvoidsayHello1();publicvoidsayHello2();publicvoidsayHello3();然后编写代理对象,该类和被代理对象一样实现接口IHello.java,只不过在代理对象中增加需要的服务,代理类ProxyHello.java代码。,15.1.1代理机制,第三步就是编写被代理类,该类实现IHello接口,代码实现如下:erfaces.impl;erfaces.IHello;publicclassHelloimplementsIHellopublicvoidsayHello1()System.out.println(sayHello1.);publicvoidsayHello2()System.out.println(sayHello2.);publicvoidsayHello3()System.out.println(sayHello3.);,15.1.1代理机制,编写一个测试类,查看效果,StaticTest.java代码编写如下:packagetest;erfaces.IHello;erfaces.impl.Hello;xyClass.ProxyHello;publicclassStaticTestpublicstaticvoidmain(Stringargs)/创建接口对象时应用代理类对象,并传递了被代理类对象作为构造方法的参数IHellohello=newProxyHello(newHello();hello.sayHello1();hello.sayHello2();hello.sayHello3();,15.1.1代理机制,运行该测试程序,控制台信息为:验证用户.sayHello1.验证用户.sayHello2.验证用户.sayHello3.,15.1.1代理机制,2动态代理动态代理是根据静态代理的机制,抽象出一个泛类代理。它不依赖任何被代理对象的代理实现,该动态代理类需要实现InvocationHandler接口,例如,实现动态代理类DynamicProxy的代码。接口和接口实现类(被代理类)不变,编写测试类代码如下:packagetest;erfaces.IHello;erfaces.impl.Hello;xyClass.DynamicProxy;publicclassDynamicTestpublicstaticvoidmain(Stringargs)DynamicProxyproxy=newDynamicProxy();IHellohello=(IHello)proxy.bind(newHello();hello.sayHello1();hello.sayHello2();hello.sayHello3();,15.1.2AOP的术语与概念,1横向关注点Cross-cuttingconcern在介绍代理机制的例子中,验证用户方法在一个应用程序中常被安排到各个处理流程之中,这些方法在AOP的术语中称为横向关注点。如图15.1所示,原来的业务流程是很单纯的,横向关注点如果直接写在负责某业务的类的流程中(例如直接写到Hello.java中),使得维护程序的成本增加。,图15.1原来的业务流程,15.1.2AOP的术语与概念,如果以后要修改类的记录功能或者移除这些服务,则必须修改所有曾撰写记录服务的程序,然后重新编译。另一方面,横向关注点混杂在业务逻辑之中,使得业务类本身的逻辑或程序的撰写更为复杂。为了加入日志与安全检查等服务,类的程序代码中就必须写入相关的Logging、Security等程序片段,如图15.2所示。,图15.2加入各种服务的业务流程,15.1.2AOP的术语与概念,2横向关注面Aspect将散落在各个业务类中的横向关注点收集起来,设计各个独立可重用的类,这种类称为横向关注面(Aspect)。对于应用程序中可重用的组件来说,以AOP的设计方式,它不用知道处理提供服务的类的存在,与服务相关的API不会出现在可重用的应用组件中,因而可提高这些组件的重用性,可以将这些组件应用到其他的应用程序中,不会因为加入了某个服务而与目前的应用框架发生耦合。不同的AOP框架对AOP概念有不同的实现方式,主要差别在于所提供的Aspect的丰富程度,以及它们如何被缝合(Weave)到应用程序中。,15.1.2AOP的术语与概念,3连接点Joinpoint连接点是指程序中的某一个点,它分得非常细致,如对象加载、构造方法可以是连接点,一个方法、一个属性、一条语句也可以是连接点。AspectJ中的连接点主要有下面的几种形式:方法调用:方法被调用时。方法执行:方法体的内容执行时。构造方法调用:构造方法被调用时。构造方法执行:构造方法体的内容执行时。静态初始化部分执行:类中的静态部分内容初始化时。对象预初始化:主要是指执行构造方法中的this()及super()时。对象初始化:在初始化一个类时。属性引用:引用属性时。属性设置:设置属性时。异常执行:异常执行时。通知执行:当一个AOP通知执行时。,15.1.2AOP的术语与概念,4切入点Pointcuts切入点是连接点的集合,它是程序中需要注入Advice的位置的集合,指明Advice要在什么条件下被触发。5通知Advice不同的参考资料对Advice的翻译不尽相同,有的翻译成通知,有的翻译成建议或增强等,不管翻译成什么,其实并不重要,因为相信大家重视的都是其应用性,本书就用“通知”这一说法。通知定义了切面中的实际实现,是指在定义好的切入点处所有执行的程序代码。Spring提供了3种通知(Advice)类型:前通知(BeforeAdvice):指在连接点之前,先执行通知中的代码。后通知(AfterAdvice):指在连接点执行后,再执行通知中的代码。后增强一般分为连接点正常返回增强及连接点异常返回增强等类型。环绕通知(ThrowAdvice):环绕通知是一种功能强大的增强,可以自由地改变程序的流程、连接点返回值等。除了可以自由添加需要的横切功能外,还需要负责主动调用连接点。,15.1.2AOP的术语与概念,6拦截器Interceptor拦截器用来实现对连接点进行拦截,从而在连接点前后加入自定义的切面模块功能。在大多数Java的AOP框架中,基本上都是应用拦截器来实现字段访问及方法调用的拦截。7目标对象Targetobject目标对象是指在基本拦截器机制实现的AOP框架中,位于拦截器链上最末端的对象实例,一般情况下,拦截器末端包含的目标对象就是实际业务对象。8AOP代理AOP代理是指在基于拦截器机制实现的AOP框架中,实际业务对象的代理对象。Spring中的AOP代理可以使用JDK动态代理,也可以使用CGLIB代理。前者为实现接口的目标对象的代理,后者为不实现接口的目标对象的代理。一般情况下都会应用到接口,一般使用JDK代理。,15.1.3Spring1.x的AOP支持,1前置通知BeforeAdvice下面举例说明。建立Spring项目,命名为“Spring_AOP1”,添加Spring的类库(核心类库、AOP类库)。编写接口IHello.java(该文件放入对应包下,代码第一行),代码如下:erfaces;publicinterfaceIHellopublicvoidsayHello1();publicvoidsayHello2();publicvoidsayHello3();,15.1.3Spring1.x的AOP支持,接口实现类Hello.java代码如下:erfaces.impl;erfaces.IHello;publicclassHelloimplementsIHellopublicvoidsayHello1()System.out.println(sayHello1.);publicvoidsayHello2()System.out.println(sayHello2.);publicvoidsayHello3()System.out.println(sayHello3.);,15.1.3Spring1.x的AOP支持,下面编写前置通知的逻辑代码,该类要实现MethodBeforeAdvice接口,并覆盖其before()方法。本例只是在控制台打印一句话,在实际的应用中可以将要做的前置服务放在before()方法体内。本例前置通知类AdviceBeforeHello.java代码如下:packageorg.aop.advice;importjava.lang.reflect.Method;importorg.springframework.aop.MethodBeforeAdvice;publicclassAdviceBeforeHelloimplementsMethodBeforeAdvicepublicvoidbefore(Methodmethod,Objectargs,Objecttarget)throwsThrowableSystem.out.println(验证用户.);在src下创建配置文件config.xml文件,代码编写。,15.1.3Spring1.x的AOP支持,编写测试类Test.java,代码如下:packagetest;erfaces.IHello;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;publicclassTestpublicstaticvoidmain(Stringargs)ApplicationContextac=newClassPathXmlApplicationContext(config.xml);IHellohello=(IHello)ac.getBean(proxy);hello.sayHello1();hello.sayHello2();hello.sayHello3();,15.1.3Spring1.x的AOP支持,运行该测试类,结果如下:验证用户.sayHello1.验证用户.sayHello2.验证用户.sayHello3.,15.1.3Spring1.x的AOP支持,2后置通知AfterAdvice后置通知和前置通知相似,不同的是在目标对象的方法执行完成后被调用,后置通知的逻辑代码类需实现AfterReturningAdvice接口,并覆盖其afterReturning()方法。后置通知类AdviceAfterHello.java代码编写如下:packageorg.aop.advice;importjava.lang.reflect.Method;importorg.springframework.aop.AfterReturningAdvice;publicclassAdviceAfterHelloimplementsAfterReturningAdvicepublicvoidafterReturning(Objectarg0,Methodarg1,Objectarg2,Objectarg3)throwsThrowableSystem.out.println(方法执行完成.);在该通知中也仅仅输出一句话,实际应用中的增强服务会在afterReturning()方法中定义。修改配置文件,在上例的配置文件中添加后置通知的注册,代码修改。,15.1.3Spring1.x的AOP支持,代码中,黑体部分是添加的内容,可以看出,注册了后置通知Bean及在拦截器名中加入了该Bean。测试类代码不变,运行结果如下:验证用户.sayHello1.方法执行完成.验证用户.sayHello2.方法执行完成.验证用户.sayHello3.方法执行完成.,15.1.3Spring1.x的AOP支持,3环绕通知AroundAdvice环绕通知相当于前置通知和后置通知的结合使用,建立一个环绕通知类需要实现MethodInterceptor接口,并覆盖其invoke()方法,例如,要实现上面例子的功能定义,环绕通知类AdviceAroundHello.java代码如下:packageorg.aop.advice;ercept.MethodInterceptor;ercept.MethodInvocation;publicclassAdviceAroundHelloimplementsMethodInterceptorpublicObjectinvoke(MethodInvocationarg0)throwsThrowableSystem.out.println(验证用户.);Objectresult=null;tryresult=ceed();finallySystem.out.println(方法执行完成.);returnresult;,15.1.3Spring1.x的AOP支持,该程序中调用了methodInvocation的preceed()方法,即调用了目标对象Hello的sayHello*()等一些方法,在这个方法的前后分别增加了验证和通知方法。修改配置文件config.xml,注册该类,代码。配置情况和前面两种相似,测试类不变,运行后也得到与前面例子“后置通知”同样的结果:验证用户.sayHello1.方法执行完成.验证用户.sayHello2.方法执行完成.验证用户.sayHello3.方法执行完成.,15.1.3Spring1.x的AOP支持,4异常通知ThrowAdvice异常通知就是程序发生异常的时候执行相关的服务。为了有异常发生,这里人为地抛出异常。编写接口IHello.java,使其有异常抛出,代码如下:erfaces;publicinterfaceIHelloExceptionpublicvoidsayHello1()throwsThrowable;publicvoidsayHello2()throwsThrowable;publicvoidsayHello3()throwsThrowable;,15.1.3Spring1.x的AOP支持,接口实现类HelloException.java,代码如下:erfaces.impl;erfaces.IHelloException;publicclassHelloExceptionimplementsIHelloExceptionpublicvoidsayHello1()throwsThrowableSystem.out.println(sayHello1.);thrownewException(异常.);publicvoidsayHello2()throwsThrowableSystem.out.println(sayHello2.);thrownewException(异常.);publicvoidsayHello3()throwsThrowableSystem.out.println(sayHello3.);thrownewException(异常.);,15.1.3Spring1.x的AOP支持,编写异常通知类,该类要实现ThrowAdvice接口,代码如下:packageorg.aop.advice;importorg.springframework.aop.ThrowsAdvice;publicclassAdviceThrowimplementsThrowsAdvicepublicvoidafterThrowing(Throwablethrowable)System.out.println(有异常抛出.);在src下编写配置文件throw.xml,代码编写。,15.1.3Spring1.x的AOP支持,编写测试类代码:packagetest;erfaces.IHelloException;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;publicclassTestExceptionpublicstaticvoidmain(Stringargs)ApplicationContextac=newClassPathXmlApplicationContext(throw.xml);IHelloExceptionhello=(IHelloException)ac.getBean(proxy);tryhello.sayHello1();hello.sayHello2();hello.sayHello3();catch(Throwablet)System.out.println(t);,15.1.3Spring1.x的AOP支持,运行该程序,结果如下:sayHello1.有异常抛出.java.lang.Exception:异常.,15.1.3Spring1.x的AOP支持,5NameMatchMethodPointAdvisor下面通过修改前置通知的实例来讲解怎么应用NameMatchMethodPointAdvisor来完成仅仅对Hello.java中的“sayHello2()”方法进行前置通知,而其他方法不进行通知,这里仅修改配置文件即可,配置文件修改。其他内容不变,运行测试程序,结果如下所示:sayHello1.验证用户.sayHello2.sayHello3.,15.1.3Spring1.x的AOP支持,6RegexpMethodPointAdvisor将上面的NameMatchMethodPointAdvisor例子用RegexpMethodPointAdvisor来完成,其他文件也不用修改,只需修改配置文件即可,代码修改。其他的程序都不变,运行测试程序,输出结果如下:sayHello1.验证用户.sayHello2.sayHello3.,15.1.4Spring2.x的AOP支持,1基于XMLSchema的前置通知通过改写Spring1.x中的前置通知的例子来完成应用XMLScheme的前置通知。首先,接口及其实现类不变,编写通知的逻辑代码AdviceBeforeHello.java,这里不用实现MethodBeforeAdvice接口,它就是一个普通的Java类,代码如下:packageorg.aop.advice;publicclassAdviceBeforeHellopublicvoidbefore()System.out.println(验证用户.);该代码中定义了before()方法,其实该方法名是任意定义的,但这里为了表示前置通知,故命名为before()。下面配置Spring的核心配置文件before.xml,代码。,15.1.4Spring2.x的AOP支持,该配置文件在Beans的属性中加入了schema的命名空间:xmlns:aop=/schema/aop/schema/aop/schema/aop/spring-aop-2.5.xsd首先来看的配置规则:,15.1.4Spring2.x的AOP支持,下面介绍配置内容:用来配置AOP的正则表达式,其他标签可以直接根据该标签的id属性来引用。这里需要注意的是,在配置正则表达式时,“*”与后面的接口之间要有一个空格,否则会提示正则表达式错误。:用来配置AOP的切面,与pointcut相同,可以直接使用advisor的id来引用该切面。:用来配置一个切面,ref指定要应用的通知类,用来配置通知的类型,adviceType有多种类型,可以是表示前置通知、表示后置通知、表示环绕通知、表示异常通知,pointcut-ref属性用来引用一个pointcut,method属性用来指定要应用的通知类中的方法。,15.1.4Spring2.x的AOP支持,编写测试类Test.java,代码如下:packagetest;erfaces.IHello;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;publicclassTestpublicstaticvoidmain(Stringargs)ApplicationContextac=newClassPathXmlApplicationContext(before.xml);IHellohello=(IHello)ac.getBean(hello);hello.sayHello1();hello.sayHello2();hello.sayHello3();,15.1.4Spring2.x的AOP支持,运行程序,结果如下:验证用户.sayHello1.验证用户.sayHello2.验证用户.sayHello3.,15.1.4Spring2.x的AOP支持,2基于Annotation的前置通知Spring2.x结合JDK5及以上版本,提供了Annotation设置AOP的通知,简化了XML的配置,更加简化了AOP实现。下面将上面的例子修改为应用Annotation来配置AOP。首先要修改通知类AdviceBeforeHello.java,代码修改如下:packageorg.aop.advice;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Before;AspectpublicclassAdviceBeforeHelloBefore(execution(*erfaces.IHello.*(.)publicvoidbefore()System.out.println(验证用户.);,15.1.4Spring2.x的AOP支持,使用Aspect标签标识该类是一个Aspect,Before标签表示该方法是一个前置通知,里面的“execution(*erfaces.IHello.*(.)”是正则表达式,和前面的例子的表达式意义相同,下面的before()方法也是自定义的方法。接下来修改XML配置文件,代码修改如下:,15.1.4Spring2.x的AOP支持,3基于XMLSchema的后置通知后置通知和前置通知相似,通知类也不使用AfterReturningAdvice接口,可以使用任意类中的任意方法作为后置通知,接口IHello.java及其实现类Hello.java不变,编写通知类代码如下:packageorg.aop.advice;publicclassAdviceAfterHellopublicvoidafter()System.out.println(方法执行完成.);编写配置文件after.xml,配置。,15.1.4Spring2.x的AOP支持,配置文件的配置方法和前置通知相似,仅仅修改了通知类型以及通知类的Bean和一些Bean的id而已。修改测试程序,加载after.xml文件,运行结果如下:sayHello1.方法执行完成.sayHello2.方法执行完成.sayHello3.方法执行完成.,15.1.4Spring2.x的AOP支持,4基于Annotation的后置通知应用Annotation来标注后置通知也非常简单,大体上和基于Annotation的前置通知相似,对前面程序进行修改,修改AdviceAfterHello.java代码如下:packageorg.aop.advice;importorg.aspectj.lang.annotation.AfterReturning;importorg.aspectj.lang.annotation.Aspect;AspectpublicclassAdviceAfterHelloAfterReturning(execution(*erfaces.IHello.*(.)publicvoidafter()System.out.println(方法执行完成.);,15.1.4Spring2.x的AOP支持,after.xml配置文件修改如下:,15.1.4Spring2.x的AOP支持,5基于XMLSchema的环绕通知同样的思路,接口IHello.java及实现类Hello.java代码不用改变,修改AdviceAroundHello.java,在环绕通知类的自定义方法中需要设置一个ProceedingJoinPoint类型的参数,环绕通知在执行完前置服务后需要使用该参数来激活AOP目标对象的相关方法,然后再执行环绕通知中的后置服务。代码修改如下:packageorg.aop.advice;importorg.aspectj.lang.ProceedingJoinPoint;publicclassAdviceAroundHellopublicObjectaround(ProceedingJoinPointjoinPoint)throwsThrowableSystem.out.println(验证用户.);Objectresult=joinPceed();System.out.println(方法执行完成.);returnresult;编写配置文件around.xml,代码。,15.1.4Spring2.x的AOP支持,测试程序稍做修改,加载配置文件“around.xml”,其他内容不变,运行结果如下:验证用户.sayHello1.方法执行完成.验证用户.sayHello2.方法执行完成.验证用户.sayHello3.方法执行完成.,15.1.4Spring2.x的AOP支持,6基于Annotation的环绕通知同样的思路,通过修改上例来完成基于Annotation的环绕通知,通知类AdviceAroundHello.java代码修改如下:packageorg.aop.advice;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;AspectpublicclassAdviceAroundHelloAround(execution(*erfaces.IHello.*(.)publicObjectaround(ProceedingJoinPointjoinPoint)throwsThrowableSystem.out.println(验证用户.);Objectresult=joinPceed();System.out.println(方法执行完成.);returnresult;,15.1.4Spring2.x的AOP支持,配置文件around.xml修改为:,15.1.4Spring2.x的AOP支持,7基于XMLSchema的异常通知下面通过修改Spring1.x的异常通知实例来讲解基于XMLSchema的异常通知,接口IHelloException.java及实现类HelloException.java不变,修改异常通知类AdviceThrow.java,代码如下:packageorg.aop.advice;publicclassAdviceThrowpublicvoidafterThrowing()System.out.println(有异常抛出.);该类无须再实现任何接口。创建一个新的配置文件throw.xml,代码修改。,15.1.4Spring2.x的AOP支持,测试程序如下:packagetest;erfaces.IHelloException;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;publicclassTestExceptionpublicstaticvoidmain(Stringargs)ApplicationContextac=newClassPathXmlApplicationContext(throw.xml);IHelloExceptionhello=(IHelloException)ac.getBean(hello);tryhello.sayHello1();hello.sayHello2();hello.sayHello3();catch(Throwablet)System.out.println(t);,15.1.4Spring2.x的AOP支持,运行结果为:sayHello1.有异常抛出.java.lang.Exception:异常.,15.1.4Spring2.x的AOP支持,8基于Annotation的异常通知基于Annotation的异常通知使用AfterThrowing,异常通知类代码修改如下:packageorg.aop.advice;importorg.aspectj.lang.annotation.AfterThrowing;importorg.aspectj.lang.annotation.Aspect;AspectpublicclassAdviceThrowAfterThrowing(execution(*erfaces.IHellException.*(.)publicvoidafterThrowing()System.out.println(有异常抛出.);,15.1.4Spring2.x的AOP支持,配置文件throw.xml代码修改为:,15.2Spring的事务支持,Spring的事务处理是基于Spring的AOP实现的,Spring事务的中心接口是org.springframework.transaction.PlatformTransactionManager,该接口的代码为:publicinterfacePlatformTransactionManager/获得目前的事务TransactionStatusgetTransaction(TransactionDefinitiondefinition)throwsTransactionException;/提交事务voidcommit(TransactionStatusstatus)throwsTransactionException;/事务回滚voidrollback(TransactionStatusstatus)throwsTransactionException;,15.2Spring的事务支持,TransactionStatus代表了目前的事务,该接口的代码为:publicinterfaceTransactionStatus/判断是否是一个新事务booleanisNewTransaction();/判断是否有保存点booleanhasSavepoint();/设定为只读事务voidsetRollbackOnly();/判断是否为只读事务booleanisRollbackOnly();/判断一个事务是否完成booleanisCompleted();,15.2Spring的事务支持,TransactionDefinition接口代表着事务处理的一些属性定义,比如事务的名称、隔离层次、传播行为、只读和超时等,该接口的代码为:publicinterfaceTransactionDefinition/获得事务的传播行为intgetPropagationBehavior();/获得事务的隔离层次intgetIsolationLevel();/判断事务是否超时intgetTimeout();/判断是否为只读事务booleanis

温馨提示

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

评论

0/150

提交评论