




已阅读5页,还剩27页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第7章在Spring中管理事务,7.1知识点:AOP简介,7.2开发步骤,7.1知识点:AOP简介,7.1.1从代理机制初探AOP从一个简单常见的例子开始。这个例子当中含有日志动作,程序中经常需要为某些动作或事件作下记录,以便随时检查程序运行过程和排除错误的信息。来看一个简单的例子,当需要在执行某些方法时留下日志信息,直觉的,可能会这样写。importjava.util.logging.*;publicclassHelloSpeakerpirvateLoggerlogger=Logger.getLogger(this.getClass().getName();publicvoidhello(Stringname)logger.log(Level.INFO,”hellomethodstarts”);/方法执行开始时留下日志Sytem.out.println(”hello,”+name);/程序的主要功能Logger.log(Level.INFO,”hellomethodends”);/方法执行完毕时留下日志,7.1.1从代理机制初探AOP,在HelloSpeaker类中,当执行hello()方法时,程序员希望开始执行该方法与执行完毕时都会留下日志,最简单的做法是用上面的程序设计,在方法执行的前后加上日志动作。然而对于HelloSpeaker来说,日志的这种动作并不属于HelloSpeaker逻辑,这使得HelloSpeaker增加了额外的职责。如果程序中这种日志动作到处都有需求,以上的写法势必造成程序员必须到处撰写这些日志动作的代码。这将使得维护日志代码的困难加大。如果需要的服务不只是日志动作,有一些非类本身职责的相关动作也混入到类中,比如权限检查,事务管理等等,会使得类的负担加重,甚至混淆类本身的职责。另一方面,使用以上的写法,如果有一天不再需要日志(或权限检查,交易管理等)的服务,将需要修改所有留下日志动作的程序,无法简单地就将这些相关服务从现有的程序中移除。可以使用代理(Proxy)机制来解决这个问题,有两种代理方式:静态代理(staticproxy)和动态代理(dynamicproxy)。在静态代理的实现中,代理类与被代理的类必须实现同一个接口,在代理类中可以实现记录等相关服务,并在需要的时候再呼叫被代理类。这样被代理类中就可以仅仅保留业务相关的职责了。,7.1.1从代理机制初探AOP,举个简单的例子,首先定义一个IHello接口:IHello.java代码如下:publicinterfaceIhellopublicvoidhello(Stringname);然后让实现业务逻辑的HelloSpeaker类别实现Ihello接口,HelloSpeaker.java代码如下:publicclassHelloSpeakerimplementsIhellopublicvoidhello(Stringname)Sytem.out.println(”hello,”+name);可以看到,在HelloSpeaker类中没有任何日志的代码插入其中,日志服务的实现将被放到代理类中,代理类同样要实现IHello接口:,7.1.1从代理机制初探AOP,HelloProxy.java代码如下:publicclassHelloProxyimplementsIhelloprivateLoggerlogger=Logger.getLogger(this.getClass().getName();privateIhellohelloObject;publicHelloProxy(IhellohelloObject)this.helloObject=helloObject;publicvoidhello(Stringname)log(”hellomethodstarts”);/日志服务helloObject.hello(name);/执行业务逻辑log(”hellomethodends”);/日志服务privatevoidlog(Stringms)logger.log(Level.INFO,msg);,7.1.1从代理机制初探AOP,在HelloProxy类的hello()方法中,真正实现业务逻辑前后可以安排记录服务,可以实际撰写一个测试程序来看看如何使用代理类。publicclassProxyDemopublicstaticvoidmain(Stringargs)IHelloproxy=newHelloProxy(newHelloSpeaker();proxy.hello(”Justin”);这是静态代理的基本示例,但是可以看到,代理类的一个接口只能服务于一种类型的类,而且如果要代理的方法很多,势必要为每个方法进行代理,静态代理在程序规模稍大时就必定无法胜任。,7.1.2动态代理,在JDK1.3之后加入了可协助开发动态代理功能的API等相关类别,不需要为特定类和方法编写特定的代理类,使用动态代理,可以使得一个处理者(Handler)为各个类服务。要实现动态代理,同样需要定义所要代理的接口:IHello.java代码如下:publicinterfaceIHellopublicvoidhello(Stringname);然后让实现业务逻辑的HelloSpeaker类别要实现IHello接口,如HelloSpeaker.java代码如下:publicclassHelloSpeakerimplementsIHellopublicvoidhello(Stringname)System.out.println(”Hello,”+name);,7.1.2动态代理,写一个测试程序,如果要使用LogHandler的bind()方法来绑定被代理类。ProxyDemo.java代码如下:publicclassProxyDemopublicstaticvoidmain(Stringargs)LogHandlerlogHandler=newLogHandler();IHellohelloProxy=(IHello)logHandler.bind(newHelloSpeaker();helloProxy.hello(”Justin”);HelloSpeaker本身的职责是显示文字,却必须插入日志动作,这使得HelloSpeaker的职责加重。在AOP的是术语中,日志的程序代码横切(cross-cutting)到HelloSpeaker的程序执行流程中,日志这样的动作在AOP中被称为横切关注点(cross-cuttingconcern)。使用代理类将记录与业务逻辑无关的动作提取出来,设计为一个服务类,如同前面的范例HelloProxy或者LogHandler,这样的类称之为切面(aspect)。AOP中的aspect所指的可以是像日志等这类的动作或服务,将这些动作(cross-cuttingconcern)设计为通用,不介入特定业务类的一个职责清楚的Aspect类,这就是所谓的Aspect-orientedprogramming,AOP。,7.1.3AOP术语与概念,介绍AOP术语和概念。Cross-cuttingconcer在DynamicProxyDemo的例子中,记录的动作原先被横切(Cross-cutting)到HelloSpeaker本身所负责的业务流程中。另外类似于日志这类的动作,如安全检查、事务等服务,在一个应用程序中常被安排到各个类的处理流程之中。这些动作在AOP的术语中被称为Cross-cuttingconncers。如图7-1所示,原来的业务流程是很单纯的。,图7-1原来的业务流程,7.1.3AOP术语与概念,Cross-cuttingconcerns如果直接写在负责某业务的类的流程中,使得维护程序的成本增加。如果以后要把类的记录功能修改或者移除这些服务,则必须修改所有撰写曾记录服务的程序,然后重新编译。另一方面,Cross-cuttingconcerns混杂在业务逻辑之中,使得业务类本身的逻辑或者程序的撰写更为复杂。如同7-2所示,为了要加入日志与安全检查等服务,类的程序代码中被硬生生地写如了相关的Logging、Security程序片段。,图7-2加入各种服务的业务流程,7.1.3AOP术语与概念,Aspect将散落在各个业务类中的Cross-cuttingconcerns收集起来,设计各个独立可重用的类,这种类称之为Aspect。例如在动态代理中将日志的动作设计为一个LogHandler类,LogHandler类在AOP术语中就是Aspect的一个具体实例。在需要该服务的时候,缝合到应用程序中;不需要服务的时候,也可以马上从应用程序中脱离。应用程序中的可重用组件不用做任何的修改,例如在动态代理中的HelloSpeaker所代表的角色就是应用程序中可重用的组件,在它需要日志服务时并不用修改本身的程序代码。另一方面,对于应用程序中可重用的组件来说,以AOP的设计方式,它不用知道处理提供服务的类的存在。即与服务相关的API不会出现在可重用的应用组件中,因而可提高这些组件的重用性,可以将这些组件应用到其他的应用程序中,而不会因为目前加入了某个服务或与目前的应用框架发生耦合。不同的AOP框架对AOP概念有不同的实现方式,主要的差别在于所提供的Aspects的丰富程度,以及它们如何被缝合(Weave)到应用程序中。,7.1.4通知Advice,Spring提供了5种通知(Advice)类型:InterceptionAround、Before、AfterReturning、Throw和Introduction。它们分别在以下情况被调用:InterceptionAroundAdvice:在目标对象的方法执行前后被调用。BeforeAdvice:在目标对象的方法执行前被调用。AfterReturningAdvice:在目标对象的方法执行后被调用ThrowAdvice:在目标对象的方法抛出异常时被调用。IntroductionAdvice:一种特殊类型的拦截通知,只有在目标对象的方法调用完毕后执行。这里,用过前置通知BeforeAdvice来说明。BeforeAdvice会在目标对象的方法执行之前被呼叫。如同在便利店里,在客户购买东西之前,老板要给它们一个热情的招呼。为了实现这一点,需要扩展MethodBeforAdvice接口。这个接口提供了获取目标方法、参数以及目标对象。publicinterfaceMethodBeforeAdvicevoidbefore(Methodmethod,Objectargs,Objecttarget)throwsThrowable,7.1.4通知Advice,用实例来示范如何使用BeforeAdvice。首先要定义目标对象必须实现的接口:IHello.java代码如下:publicinterIHellopublicvoidhello(Stringname);接着定义一个HelloSpeaker了,让它实现IHello接口:HelloSpeaker.java代码如下:publicclassHelloSpeakerimplementsIHellopublicvoidhello(Stringname)System.out.println(“Hello,”+name);在对HelloSpeader不进行任何修改的情况下,想要在hello()方法执行之前,可以记录一些信息,有一个组件,但是没有源代码,但是想对它增加一些日志的服务。可以先实现MethodBeoforeAdvice接口,例如:,7.1.4通知Advice,LogBeforeAdvice.java代码如下:importjava.lang.reflect.Method;importjava.util.logging.Level;importjava.util.logging.Logger;importorg.springframework.aop.MethodBeforeAdvice;publicclassLogBeforeAdviceimplementsMethodBeforAdviceprivateLoggerlogger=Logger.getLogger(this.getClass().getName();publicvoidbefore(Mehodmethod,Objectargs,Objecttarget)throwsThrowablelogger.log(Levl.INFO,”methodstarts”+method);,7.1.4通知Advice,在before()方法中,加入了一些记录信息的程序代码。LogBeforeAdvice类被设计为一个独立的服务,接着只要在定义文档中如下定义:beans-config.xml代码如下:IHellologBeforeAdvice,7.1.4通知Advice,注意,除了建立Advice和Target实例之外,还使用了org.springframework.aop.framework.ProxyBean。这个类会被BeanFactory或者ApplicationContext用来建立代理对象。需要在“proxyInterfaces”属性中告诉代理可运行的界面,在“target”上告诉Target对象,在“interceptorNames”上告诉要应用的Advice实例,在不指定目标方法的时候,BeforeAdvice会被缝合(Weave)到界面上多处有定义的方法之前。写一个程序测试一下BeforeAdvice的运作:SpringAOPDemo.java代码如下:importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.FileSystemXmlApplicationContext;publicclassSpringAOPDemopublicstaticvoidmain(Stringargs)ApplicationContextcontext=newFileSystemXmlApplicationContext(“bean-config.xml”);IHellohelloProxy=(IHello)context.getBean(“helloProxy”);helloProxy.hello(“Justin”);HelloSpeaker与LogBeforeAdvice是两个独立的类。对于HelloSpeaker来说,它不用知道LogBeforeAdvice的存在;而LogBeforeAdvice也可以运行到其他类之上。HelloSpeaker与LogBefore都可以重复使用。,7.1.5切入点PointCut,Pointcut定义了通知Advice应用的时机。从一个实例开始,介绍如何使用Spring提供的org.springframework.aop.support.NameMatchMethodPointcutAdvisor。可以指定Advice所要应用的目标上的方法名称,或者是用*来指定。例如,hello*表示调用代理对象上以hello作为开头的方法名称时,都会应用指定的Advices。IHello.java代码如下:publicinterfaceIHellopublicvoidhelloNewbie(Stringname);publicvoidhelloMaster(Stringname);HelloSpeaker类实现IHello接口。HelloSpeaker.java代码如下:publicclassHelloSpeakerpublicvoidhelloNewbie(Stringname)System.out.println(”Hello,”+name+”newbie!”);publicvoidhelloMaster(Stringname)System.out.println(”Hello,”+name+”master!”);,7.1.5切入点PointCut,编写一个简单的Advice,这里使用BeforeAdviece中LogBeforeAdvice。定义Bean文档,使用NameMatchMethodPointcutAdvisor将Pointcut与Advice结合在一起:bean-config.xml代码如下:hello*,7.1.5切入点PointCut,IHellohelloAdvisor,7.1.5切入点PointCut,在NameMatchMethodPointcutAdvosor的“mappedName”属性上,由于指定了“hello*”,所以当调用helloNewbie()或者helloMaster()方法时,由于方法名称的开头符合“hello”,就会应用logBeforeAdvice的服务逻辑,可以写一下程序来测试。SpringAOPDemo.java代码如下:importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.FileSystemXmlApplicationContext;publicclassSpringAOPDemopublicstaticvoidmain(Stringargs)ApplicationContextcontext=newFileSystemXmlApplicationContext(“bean-config.xml”);IHellohelloProxy=(IHello)context.getBean(“helloProxy”);helloProxy.helloNewbie(“Justin”);helloProxy.helloMaster(“Tom”);,7.1.5切入点PointCut,在Spring中使用PointcutAdvisor把Pointcut与Advice结合为一个对象。Spring中大部分内建的Pointcut都有对应的PointA.springframework.aop.support.NameMatchMethodPointcutAdvisor,这是最简单的PointAdvisor,它是Spring中静态的Pointcut实例。使用org.springframework.aop.support.RegexpMethodPointcut可以实现静态切入点,RegexpMethodPointcut是一个通用的正则表达式切入点,它是通过JakartaORO来实现的。静态切入点只限于给定的方法和目标类,而不考虑方法的参数。动态切入点与静态切入点的区别是,它不仅限定于给定的方法和类,动态切入点还可以指定方法的参数。当切入点需要在执行时根据参数值来调用通知时,就需要使用动态切入点。在大多数的切入点可以使用静态切入点,很少有机会创建动态切入点。,7.1.6Spring对事务的支持,事务的特性之一是原子(Atomic)性。如对数据库存取,就是一组SQL指令,这一组SQL指令必须全部执行成功;如果因为某个原因(例如其中一行SQL有错误),则先前所执行过的SQL指令撤销。在JDBC中,可以用Connection的setAutoCommit()方法,给定它false参数。在一连串的SQL语句后面,调用Connection的commit()来送出变更。如果中间发生错误,则调用rollback()来撤销所有的执行,例如:tryconnection.setAutoCommit(false);/一连串SQL操作mit();/执行成功,提交所有变更catch(SQLExceptione)connection.rollback();/发生错误,撤销所有变更,7.1.6Spring对事务的支持,在Spring中对JDBC的事务管理加以封装,Spring事务管理的抽象关键在于org.springframwork.transaction.PlatformTransactionManager接口的实现。PlatformTransactionManager接口有许多事务实现类别,如DataSourceTransactionManager、HibernateTransactionManager、JdoTransactionManager、JtaTransactionManager等。借助PlatformTransactionManager接口和各种技术实现,Spring在事务管理上可以让开发人员使用一致的编程模式。事务的失败通常是致命的错误,Spring不强迫一定要处理,而让开发者自行选择是否要捕捉异常。Spring提供编程式的事务管理(Programmatictransactionmanagement)与声明式的事务管理(Declarativetransactionmanagement):编程式的事务管理编程式的事务管理可以清楚的控制事务的边界,即自行实现事务何时开始、撤销、结束等,可以实现细力度的事务控制。,7.1.6Spring对事务的支持,声明式的事务管理然而在多数情况下,事务并不需要细粒度的控制,采用声明式的事务管理,优点是Spring事务管理的相关API可以不用介入程序之中,从对象的角度来看,并不知道它正被纳入事务管理之中,不需要事务管理的时候,只要在设定档案上修改一些设定,就可以移除事务管理服务。这里,主要介绍声明式事务管理。Spring的声明式事务管理依赖AOP框架来完成。使用声明式事务管理的好处是事务管理不侵入开发组件。即DAO组件不会意识到正在事务管理之中。如果想要改变事务管理策略,只需要在定义文档中重新组态即可。例如,可以在不修改UserDAO类的情况下,为这个类加入事务管理的服务。一个简化的方法是使用TransactionProxyFactoryBean,指定要介入的事务管理对象机器方法,这里需要修改定义文档,如下所示:bean-config.xml代码如下:,7.1.6Spring对事务的支持,TransactionProxyFactoryBean需要一个TransactionManager,如果是JDBC,可以使用DataSourceTransactionManagr。由于这里使用的是Hibernate,所以使用org.springframework.orm.hibernate3.HibernateTransactionManag。TransactionProxyFactoryBean是代理类,“target”属性指定要代理的对象,事务管理会自动介入指定的方法前后。这里是指“transactionAttributes”属性指定,insert*表示指定方法名称insert开头的全部纳入事务管理。也可以指定方法全名,如果在方法执行过程中发生错误,则所有先前的操作自动撤回,否则正常提交。insert*等方法上指定“PROPAGATION_REQUIRED”,表示在目前的事务执行操作中,如果事务不存在就创建一个新的,相关的意义可以在API文件中TransactionDefinition接口中找到。可以加上多个事务定义,中间使用逗号“,”隔开。例如,可以加上只读,或者是指定某个例外发生时撤回操作:PROPAGATION_REQUIRED,readOnly,-MyCheckedExceptionMyCheckedException前面加上“”时,表示发生指定异常撤销操作,如果加上“”,表示发生异常时立即提交。,7.1.6Spring对事务的支持,由于userDAO被userDAOProxy代理了,所以要做的是取得userDAOProxy,而不是userDAO。例如:SpringAOPDemo.javaimportorg.springframework.context.ApplicationContext;importorg.springframework.context.suppor
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 工程师资质及经验证明书(5篇)
- 电子发票开具及报销流程规定合同书
- 2025年音乐教育专业考试题及答案
- 2025年创新创业实践与管理能力测试卷及答案
- 2025年甘肃省平凉华亭市策底镇招聘专业化管理的村文书笔试备考试题及答案详解1套
- 物资采购基本管理制度
- 特殊幼儿患病管理制度
- 特殊材料入库管理制度
- 率土之滨团队管理制度
- 玩具挂件库存管理制度
- 工模外发管理流程模板
- 部编版高一上册语文第三课《百合花》课文原文教案及知识点
- 北京理工附中小升初分班考试真题
- 膀胱镜检查记录
- 英语社团活动课件
- 学前儿童发展心理学-情感
- 二年级下册数学教案 《生活中的大数》练习课 北师大版
- GB∕T 16762-2020 一般用途钢丝绳吊索特性和技术条件
- 电网施工作业票模板
- T∕CAEPI 31-2021 旋转式沸石吸附浓缩装置技术要求
- 国家级高技能人才培训基地建设项目实施管理办法
评论
0/150
提交评论