Spring中AOP基于Annotation的零配置(1)
来源:互联网 发布:破解二维码软件 编辑:程序博客网 时间:2024/05/19 11:37
一、AOP需要程序员参与的三个部分:
1、定义普通业务组件
2、定义切入点,一个切入点可能横切多个业务组件
3、定义曾强处理,增强处理就是AOP框架为普通业务组件织入的处理动作
一旦定义了合适的切入点和增强处理,AOP框架将会自动生成AOP代理,而AOP代理方法大致有如下公式:
代理对象的方法 = 增强处理 + 被代理对象的方法
建议使用AspectJ方式来定义切入点和增强处理,在这种公式下,Spring依然有如下两种选择来定义切入点和增强处理
①基于Annotation的“零配置”方式:使用@Aspect、@Pointcut等Annotation来标注切入点和增强处理
②基于XML配置文件的管理方式:使用SPring配置文件来定义切入点和增强处理
二、Spring依然采用运行时生成动态代理的方式来增强目标对象,所以它不需要增加额外的编译,也不需要AspectJ的织入器支持;而AspectJ在采用编译时增强,所以AspectJ需要使用自己的编译器来编译Java文件,还需要织入器。
为启动Spring对@AspectJ切面配置的支持,并保证Spring容器的目标Bean被一个或多个切面自动增强,必须Spring配置文件中配置如下片段:
bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="html"><!-- Spring配置文件的根元素,使用spring-beans-3.0.xsd语义约束 --><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns="http://www.springframework.org/schema/beans"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><!-- 指定自动搜索Bean组件、自动搜索切面类 --><context:component-scan base-package="tju.chc.app.service.impl,tju.chc.app.service"><context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/></context:component-scan><!-- 启动!AspectJ支持 --><aop:aspectj-autoproxy/><bean id="korea" class="tju.chc.app.service.impl.Korea" /></beans>
TxApect增强处理
public aspect TxAspect {//指定执行Hello.sayHello()方法时执行下面代码块void around():call(void Hello.sayHello()){System.out.println("开始事务");proceed();System.out.println("事物结束");}}
BeforeAdvice增强处理
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">定义Before增强处理</span>
package tju.chc.aspectJTest;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspectpublic class BeforeAdviceTest {//匹配 包下所有的类的所有方法的执行 作为切入点@Before("execution(* tju.chc.app.service.impl.*.*(..))")public void authority(){System.out.println("before 切入");}}
定义AfterReturning增强处理
package tju.chc.aspectJTest;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.Aspect;@Aspectpublic class AfterReturningAdviceTest {//匹配tju.chc.app.service.impl包下所有类的所有方法的执行作为切入点@AfterReturning(returning="rvt",pointcut="execution(* tju.chc.app.service.impl.*.*(..))")public void log(Object rvt){System.out.println("获取目标方法返回值:" + rvt);System.out.println("模拟记录日志功能。。。");}}
输出
开始事务Hello AspectJ!事物结束before 切入获取目标方法返回值:adfHello , SPring AOP模拟记录日志功能。。。adfHello , SPring AOPbefore 切入Korea eat 泡菜获取目标方法返回值:null模拟记录日志功能。。。
4AfterThrowing增强处理
package tju.chc.aspectJTest;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;@Aspectpublic class AfterThrowingAdviceTest {//匹配 包下所有类的所有方法的执行作为切入点@AfterThrowing(throwing ="ex",pointcut="execution(* tju.chc.app.service.impl.*.*(..))")public void doRecoveryActions(Throwable ex){System.out.println("目标方法中抛出的异常:"+ ex);System.out.println("模拟抛出异常增强处理");}}
Korea类增加的两个方法
//定义一个sayHi方法public String sayHi(String name){try{System.out.println("start running");new FileInputStream("a.txt");}catch(Exception ex){System.out.println("目标异常处理" + ex.getMessage());}return name + ", Hi,Spring AOP";}public void divide(){int a = 5 / 0;System.out.println("divide compelete");}
输出
----------------------sayHi
before 切入
start running
目标异常处理a.txt (系统找不到指定的文件。)
获取目标方法返回值:mashang6, Hi,Spring AOP
模拟记录日志功能。。。
----------------------divide
before 切入
目标方法中抛出的异常:java.lang.ArithmeticException: / by zero
模拟抛出异常增强处理
Exception in thread "main" java.lang.ArithmeticException: / by zero
at tju.chc.app.service.impl.Korea.divide(Korea.java:36)
at tju.chc.aspectJTest.Hello.main(Hello.java:25)
5、After增强处理
与AfterReturning增强处理优点类似,但也有区别:
①AfterReturning增强处理只有在目标方法成功完成后才会被织入
②After增强处理不管目标方法如何结束(包括成功完成和遇到异常终止两种情况),它都会被织入
因此After增强处理必须准备处理正常返回和异常返回两种情况,这种增强处理通常用于释放资源。
package tju.chc.aspectJTest;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;@Aspectpublic class AfterAdviceTest {//匹配包下所有类的所有方法的执行作为切入点@After("execution(* tju.chc.app.service.impl.*.*(..))")public void release(){System.out.println("模拟方法结束后的释放资源。。。");}}
输出
目标方法中抛出的异常:java.lang.ArithmeticException: / by zero模拟抛出异常增强处理模拟方法结束后的释放资源。。。Exception in thread "main" java.lang.ArithmeticException: / by zeroat tju.chc.app.service.impl.Korea.divide(Korea.java:36)at tju.chc.aspectJTest.Hello.main(Hello.java:25)
6.Around增强处理
Around 增强处理既可以在执行目标方法之前织入增强动作,也可以执行目标方法之后织入增强动作
Around增强处理可以决定目标方法在什么时候执行,如何执行,甚至可以完全阻止方法的执行
可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值
(通常需要在线程安全的环境下使用,因此如果普通的Before增强处理和AfterReturning 增强处理就能解觉得问题,就没必要使用Around)
当定义一个Around增强处理方法时,该方法的第一个形参必须是ProceedingJoinPoint类型(至少包含一个形参),在增强处理方法体内,调用ProceedingJoinPoint的proceed()方法才会执行目标方法(这就是Around可以完全控制目标方法执行时机。如何执行的关键;如果程序没有调用ProceedingJoinPoint的proceed()方法,则目标方法不会执行)
调用ProceedingJoinPoint的proceed()方法时,还可以传入一个Object【】对象,该数组中的值将被出入目标方法作为执行方法的实参。(用于改变目标方法的的参数)
切面定义如下
package tju.chc.aspectJTest;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;@Aspectpublic class AroundAdviceTest {//匹配包下的所有类的所有方法的执行作为切入点@Around("execution(* tju.chc.app.service.impl.*.*(..))")public Object processTx(ProceedingJoinPoint pjp) throws Throwable{System.out.println("z执行目标方法之前,模拟开始事务");//执行目标方法,并保存目标方法执行后的返回值Object ret = pjp.proceed(new String[]{"被改变的参数"});System.out.println("z执行目标方法之后,模拟结束事务。。。");//该变目标方法的返回值return ret + " new added content"; }}
输出
before 切入z执行目标方法之前,模拟开始事务获取目标方法返回值:被改变的参数Hello , SPring AOP模拟记录日志功能。。。z执行目标方法之后,模拟结束事务。。。模拟方法结束后的释放资源。。。被改变的参数Hello , SPring AOPnew added contentbefore 切入z执行目标方法之前,模拟开始事务Korea eat 被改变的参数获取目标方法返回值:null模拟记录日志功能。。。z执行目标方法之后,模拟结束事务。。。模拟方法结束后的释放资源。。。----------------------sayHibefore 切入z执行目标方法之前,模拟开始事务start running目标异常处理a.txt (系统找不到指定的文件。)获取目标方法返回值:被改变的参数, Hi,Spring AOP模拟记录日志功能。。。z执行目标方法之后,模拟结束事务。。。模拟方法结束后的释放资源。。。----------------------dividebefore 切入z执行目标方法之前,模拟开始事务目标方法中抛出的异常:java.lang.ClassCastException: java.lang.String cannot be cast to org.aspectj.lang.JoinPoint模拟抛出异常增强处理模拟方法结束后的释放资源。。。Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to org.aspectj.lang.JoinPointat tju.chc.app.service.impl.Korea$AjcClosure9.run(Korea.java:1)at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:221)at tju.chc.aspectJTest.AroundAdviceTest.processTx(AroundAdviceTest.java:16)at tju.chc.app.service.impl.Korea.divide(Korea.java:35)at tju.chc.aspectJTest.Hello.main(Hello.java:25)
7、访问目标函数的参数
在定义增强处理方法时将第一个参数定义为JoinPoint类型,当该类型增强处理方法被调用时,该JoinPoint参数就代表了织入曾强处理的连接点。JoinPoint中几个常用的方法
Object[] getArgs():返回执行目标方法时的参数
Signature getSignature() 放回被增强的方法的相关信息
Object getTarget() :返回被织入增强处理的目标对象
Object getThis() : 返回AOP框架为目标对象生成的代理对象
@Aspectpublic class FourAdviceTest {// 匹配包下的所有类的所有方法的执行作为切入点@Around("execution(* tju.chc.app.service.impl.*.*(..))")public Object processTx(ProceedingJoinPoint pjp) throws Throwable {System.out.println("Around增强:z执行目标方法之前,模拟开始事务");//访问执行目标方法的参数Object[] args = pjp.getArgs();//当执行目标方法的参数存在且第一个参数是字符串参数if(args != null && args.length > 0 && args[0].getClass() == String.class){//改变第一个目标方法的第一个参数args[0] = "被改变参数4";}// 执行目标方法,并保存目标方法执行后的返回值Object ret = pjp.proceed(args);System.out.println("Around增强:z执行目标方法之后,模拟结束事务。。。");// 该变目标方法的返回值return ret + " new added content";}//Before增强处理 匹配 包下所有的类的所有方法的执行 作为切入点@Before("execution(* tju.chc.app.service.impl.*.*(..))")public void authority(JoinPoint jp){System.out.println("Before 增强处理:模拟执行权限检查!");//返回被织入增强处理目标方法System.out.println("Before增强:被织入增强处理目标方法为:" + jp.getSignature().getName());//访问执行目标方法的参数System.out.println("Before增强:目标方法的参数为:" + Arrays.toString(jp.getArgs()));//访问被增强处理的目标对象System.out.println("Before增强:被织入增强处理的目标对象为:" + jp.getTarget());}// After 增强处理执行 匹配 包下所有类的所有方法的执行作为切入点@After("execution(* tju.chc.app.service.impl.*.*(..))")public void release(JoinPoint jp) {System.out.println("After 增强处理:模拟方法结束后的释放资源。。。");//返回被织入增强处理目标方法System.out.println("After 增强:被织入增强处理目标方法为:" + jp.getSignature().getName());//访问执行目标方法的参数System.out.println("After 增强:目标方法的参数为:" + Arrays.toString(jp.getArgs()));//访问被增强处理的目标对象System.out.println("Atfer 增强:被织入增强处理的目标对象为:" + jp.getTarget());}//定义AfterReturning增强处理执行 匹配tju.chc.app.service.impl包下所有类的所有方法的执行作为切入点@AfterReturning(returning="rvt",pointcut="execution(* tju.chc.app.service.impl.*.*(..))")public void log(JoinPoint jp, Object rvt){System.out.println("AfterReturning 增强处理:模拟记录日志功能。。。");//返回被织入增强处理目标方法System.out.println("AfterReturning 增强:被织入增强处理目标方法为:" + jp.getSignature().getName());//访问执行目标方法的参数System.out.println("AfterReturning 增强:目标方法的参数为:" + Arrays.toString(jp.getArgs()));//访问被增强处理的目标对象System.out.println("AfterReturning 增强:被织入增强处理的目标对象为:" + jp.getTarget());}}
输出:
before 切入z执行目标方法之前,模拟开始事务Around增强:z执行目标方法之前,模拟开始事务Before 增强处理:模拟执行权限检查!Before增强:被织入增强处理目标方法为:sayHelloBefore增强:目标方法的参数为:[adf]Before增强:被织入增强处理的目标对象为:tju.chc.app.service.impl.Korea@55d96549Around增强:z执行目标方法之后,模拟结束事务。。。After 增强处理:模拟方法结束后的释放资源。。。After 增强:被织入增强处理目标方法为:sayHelloAfter 增强:目标方法的参数为:[adf]Atfer 增强:被织入增强处理的目标对象为:tju.chc.app.service.impl.Korea@55d96549AfterReturning 增强处理:模拟记录日志功能。。。AfterReturning 增强:被织入增强处理目标方法为:sayHelloAfterReturning 增强:目标方法的参数为:[adf]AfterReturning 增强:被织入增强处理的目标对象为:tju.chc.app.service.impl.Korea@55d96549获取目标方法返回值:被改变参数4Hello , SPring AOP new added content模拟记录日志功能。。。z执行目标方法之后,模拟结束事务。。。模拟方法结束后的释放资源。。。被改变参数4Hello , SPring AOP new added content new added contentbefore 切入z执行目标方法之前,模拟开始事务Around增强:z执行目标方法之前,模拟开始事务Before 增强处理:模拟执行权限检查!Before增强:被织入增强处理目标方法为:eatBefore增强:目标方法的参数为:[泡菜]Before增强:被织入增强处理的目标对象为:tju.chc.app.service.impl.Korea@55d96549Korea eat 被改变参数4Around增强:z执行目标方法之后,模拟结束事务。。。After 增强处理:模拟方法结束后的释放资源。。。After 增强:被织入增强处理目标方法为:eatAfter 增强:目标方法的参数为:[泡菜]Atfer 增强:被织入增强处理的目标对象为:tju.chc.app.service.impl.Korea@55d96549AfterReturning 增强处理:模拟记录日志功能。。。AfterReturning 增强:被织入增强处理目标方法为:eatAfterReturning 增强:目标方法的参数为:[泡菜]AfterReturning 增强:被织入增强处理的目标对象为:tju.chc.app.service.impl.Korea@55d96549获取目标方法返回值:null模拟记录日志功能。。。z执行目标方法之后,模拟结束事务。。。模拟方法结束后的释放资源。。。----------------------sayHibefore 切入z执行目标方法之前,模拟开始事务Around增强:z执行目标方法之前,模拟开始事务Before 增强处理:模拟执行权限检查!Before增强:被织入增强处理目标方法为:sayHiBefore增强:目标方法的参数为:[mashang6]Before增强:被织入增强处理的目标对象为:tju.chc.app.service.impl.Korea@55d96549start running目标异常处理a.txt (系统找不到指定的文件。)Around增强:z执行目标方法之后,模拟结束事务。。。After 增强处理:模拟方法结束后的释放资源。。。After 增强:被织入增强处理目标方法为:sayHiAfter 增强:目标方法的参数为:[mashang6]Atfer 增强:被织入增强处理的目标对象为:tju.chc.app.service.impl.Korea@55d96549AfterReturning 增强处理:模拟记录日志功能。。。AfterReturning 增强:被织入增强处理目标方法为:sayHiAfterReturning 增强:目标方法的参数为:[mashang6]AfterReturning 增强:被织入增强处理的目标对象为:tju.chc.app.service.impl.Korea@55d96549获取目标方法返回值:被改变参数4, Hi,Spring AOP new added content模拟记录日志功能。。。z执行目标方法之后,模拟结束事务。。。模拟方法结束后的释放资源。。。----------------------dividebefore 切入z执行目标方法之前,模拟开始事务模拟方法结束后的释放资源。。。Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to org.aspectj.lang.JoinPointat tju.chc.app.service.impl.Korea$AjcClosure19.run(Korea.java:1)at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:221)at tju.chc.aspectJTest.AroundAdviceTest.processTx(AroundAdviceTest.java:15)at tju.chc.app.service.impl.Korea.divide(Korea.java:35)at tju.chc.aspectJTest.Hello.main(Hello.java:25)
- Spring中AOP基于Annotation的零配置(1)
- Spring中AOP基于Annotation的零配置(2)
- Spring AOP Annotation 的“零配置” 的学习方法(一)
- Spring中基于配置XML与Annotation注解配置AOP
- Spring中AOP基于Annotation配置常用声明
- Spring中的AOP—基于Annotation的配置方式
- 基于Annotation的Spring AOP: @Before
- 基于Annotation的Spring AOP: @AfterReturning
- 基于Annotation的Spring AOP: @AfterThrowing
- 基于Annotation的Spring AOP: @After
- 基于Annotation的Spring AOP: @Around
- Spring基于annotation的AOP(AspectJ)
- Spring AOP 的引入(三 基于annotation)
- Spring AOP功能--基于Annotation的方式
- 基于Annotation的零配置方式--AspectJ
- Spring的零配置(Annotation)
- spring AOP零配置
- spring中AOP的Annotation使用流程
- VC++的LNK1102 error out of memory 问题
- 读书笔记:java多线程中的volatile
- ASP.net MVC 网站发布 navbar 背景图片丢失 ArcGIS Web 开发学习(五)
- ajax异步请求详解
- NYOJ-116-士兵杀敌(二)
- Spring中AOP基于Annotation的零配置(1)
- Plus One
- 627A - XOR Equation 数学
- 夯实基础——Java基本数据类型、应用类型和转换
- CentOS安装远程桌面VNC
- form标签的几点
- FZU 2107 Hua Rong Dao (DFS)
- java中子类继承父类程序执行顺序
- 部分和问题