广西住房和城乡建设厅培训中心官方网站成都 html5网站

当前位置: 首页 > news >正文

广西住房和城乡建设厅培训中心官方网站,成都 html5网站,廊坊优化软件,深圳光明区AOP#xff08;Aspect Oriented Programming#xff09;#xff0c;是一种设计思想。先看一下百度百科的解释#xff1a; 在软件业#xff0c;AOP为Aspect Oriented Programming的缩写#xff0c;意为#xff1a;面向切面编程#xff0c;通过预编译方式和运行期间动态…AOPAspect Oriented Programming是一种设计思想。先看一下百度百科的解释 在软件业AOP为Aspect Oriented Programming的缩写意为面向切面编程通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续是软件开发中的一个热点也是Spring框架中的一个重要内容是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离从而使得业务逻辑各部分之间的耦合度降低提高程序的可重用性同时提高了开发的效率。可以看出AOP是一种设计思想也就是面向切面它是面向对象编程的一种补充和完善它是i同预编译方式和运行期间通过动态代理实现再不修改源代码的情况下添加额外功能的一种技术。 如不太了解代理模式可以看另一类23模式–代理模式 概念了解 再演示AOP之前应该先了解一些相关的疏于。 比如切面通知等。 横切关注点 先看一下百度百科的解释 横切关注点指的是一些具有横越多个模块的行为使用传统的软件开发方法不能够达到有效的模块化的一类特殊关注点。在‘面向切面’软件开发中横切关系是程序中和其他模块有联系的‘切面’。这些关系在程序模块化的设计和实现中无法被自然地分解到模块中导致或代码过于分散或代码冲突或者两者都有。举个例子来说编写一个处理医生记录的app这些记录的索引是核心模块同时关于存储记录或用户信息的数据的历史日志或者登录的验证系统由于和app中大部分模块都有关系所以成为了‘横切关系’。 其实很简单理解就是在多个代码块中有有一些代码会在多个模块中出现它们就被成为横切关注点。 举个经典例子就是日志功能日志公共往往横跨系统中的每个业务模块也就是横切所有需要日志功能的方法或者类。所以称为日志功能成为横切整个系统的关注点即日志公共可能称为横切关注点。 日志功能的代码可以抽取处理其非当前模块的核心业务当然项目中不一定只有一个横切关注点。不过横切关注点不是语法层次的天然存在而是根据附加功能逻辑上的需要。 通知 前面知道了横切关注点同时可以将其共拥有的代码提出出来。当然每一个横切关注点都需要写一个方法来实现整个方法就是通知方法。 也就是例子中的日志记录代码通过一个方法实现而不是在所有的使用日志代码的模块中写一遍。而整个实现日志记录功能的方法就叫做通知方法。 前面说过AOP用到了代理模式所以这个通知方法放置的位置不同而通知方法得到的通知也有如下分类 前置通知在被代理的目标方法前执行。返回通知在被代理的目标方法成功完成后执行。异常通知在被代理的目标方法异常完成后执行。后置通知在被代理的目标方法无论成功完成或异常完成后执行。环绕通知使用try-catch-finally结构环绕整个被代理的目标方法当然包括上面四种通知对应的所有位置。 其实通知的执行顺序还有有不同的 在5.3版本之前 前置通知——–目标操作——–后置通知——–返回通知或者异常通知。在5.3版本之后 前置通知–》目标操作——–返回通知或者异常通知——–后置通知。 切面 前面既然提取好通知方法了将其单独进行封闭方便有需要使用这通知方法模板使用。而这种封装通知方法的类被称为切面或者说是切面类。 目标被代理对象和代理 一般被代理的对象就是目标对象比如哪些核心模块需要拥有日志功能而这核心模块就是目标。 通过代理模式而给目标对象扩展新功能也就是调用切面类的通知方法的类就是代理对象。 连接点 这也是一个纯逻辑概念不是语法定义的简单说就是可以被拦截的点。 因为Spring只支持方法类型的连接点所以在Spring中连接点指的就是被拦截到的方法实际上连接点还可以是字段或者构造器。 也就是在spring中目标类的方法都可以说都有连接点毕竟都可以被拦截。 切入点 前面连点说到比如在spring中目标类的方法都可以说是连接点。但是对于开发者来说这些连接点不都是需要进行拦截扩展功能而需要自己通过条件进行定位某个连接点。 简单的说里面有共性功能的方法在提取这些非核心共有的代码之前被称之为切入点。 所以整个就涉及到连接点和切入点的区别连接点指所有的方法切入点仅指那些有共享功能的方法。 织入 毕竟提取了共有部分还是需要其生效的所以找到了切入点将提取这些非核心共有的代码回填的动态过程叫做织入。 通过了解AOP中的一些概念可以看出AOP的作用 简化代码把方法中固定位置的重复共有代码抽取出来让被抽取的方法专注于自己的核心功能提高了内聚性。同时也减少了代码的重复。代码增强把特定的功能封装到切面类中,看哪里有需要,就往上套,被套用了切面逻辑的方法就被切面给增强了. 代码演示–通过注解 代码演示通过AspectJ这个个面向切面的框架。AspectJ定义了AOP语法它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。 既然需要这个框架既然是需要导入这个jar包的在spring再导入一个spring-aspects-..*.jar 。 因为通过maven所以直接再pom.xml中配置依赖即可。 !– https://mvnrepository.com/artifact/org.springframework/spring-aspects – dependencygroupIdorg.springframework/groupIdartifactIdspring-aspects/artifactIdversion5.3.24/version /dependency然后肯定再spring配置文件中进行扫描为了方便我们直接这样配置 context:component-scan base-packagecom.xzd.aoptest /context:component-scan同时需要开启在xml头部添加xmlns:aop“http://www.springframework.org/schema/aop” beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd context:component-scan base-packagecom.xzd.aoptest /context:component-scan !– 开启aop注解功能–aop:aspectj-autoproxy/aop:aspectj-autoproxy /beans还需了解一个注解Aspect,这个注解放在切面类上面告诉jvm虚拟机来说这个是一个切面类具体如何使用可以在前提中的切面类中查看。 前面说到了几种通知当然AspectJ自然有对应的注解 注解描述Before前置通知也就是在被代理的目标方法前执行。After后置通知,在被代理的目标方法无论成功完成或异常完成后执行。AfterReturning返回通知,在被代理的目标方法成功完成后执行。AfterThrowing异常通知,在被代理的目标方法异常完成后执行。Around环绕通知,使用try-catch-finally结构环绕整个被代理的目标方法当然包括上面四种通知对应的所有位置。 前提 创建一个接口一个实现接口类还有一个就是切面类。 接口 public interface Calculate {int add(int a,int b);int sub(int a,int b);int mul(int a,int b);int div(int a,int b); } 实现接口类 // 只是简单的印证而已所以传入的数据都已满足不进行数据转换了 // 因为使用注解所以通过注解实现bean的创建 Component public class CalculateImpl implements Calculate {Overridepublic int add(int a, int b) {int i ab;System.out.println(被代理目标执行的add);return i;}Overridepublic int sub(int a, int b) {int i a-b;System.out.println(被代理目标执行的sub);return i;}Overridepublic int mul(int a, int b) {int i a*b;System.out.println(被代理目标执行的mul);return i;}Overridepublic int div(int a, int b) {int i a/b;System.out.println(被代理目标执行的div);return i;} }先提炼出来一个切面类记得在切面类上添加注解Aspect提示这个切面类 //这是一个切面类 通过注解实现创建对象bean Component //通过aspects框架注解告诉系统这个是一个切面类 Aspect public class LogAspects {} 测试类 public class testaop {Testpublic void test1(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring_test.xml);//这里返回的是接口类Calculate calculate (Calculate) applicationContext.getBean(calculateImpl);} } 前置通知–Before 看一下其属性 Before(value 切入点表达式或命名切入点,argNames 指定命名切入点方法参数列表参数名字可以有多个用“,”分隔) 先来一个小例子然后聊 //这是一个切面类 通过注解实现创建对象bean Component //通过aspects框架注解告诉系统这个是一个切面类 Aspect public class LogAspects {Before(execution(public int com.xzd.aoptest.CalculateImpl.add(int,int)))public void beforeMethod(){System.out.println(调用目标的方法之前调用);}} 其实上面的注解省略 全写法是 Before(value execution(public int com.xzd.aoptest.CalculateImpl.add(int,int)))很多注解中value都是可以省略的所以一般使用的时候为了方便使用直接省略掉value。 这个可以看出在Before中有一个execution关键字不要问为什么这样写。很简单因为是文档要求先看一下运行结果。 Testpublic void test1(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring_test.xml);//这里返回的是接口类Calculate calculate (Calculate) applicationContext.getBean(calculateImpl);System.out.println(calculate.add(1,2));}没有问题可以实现了前置通知这个时候需要具体聊一下关键字execution。 execution 这个其实就是描述了需要连接点中的具体切入点是哪里比如上面切入点是add方法 Before(execution(public int com.xzd.aoptest.CalculateImpl.add(int,int)))为什么在写切入点的社会需要将方法修饰范围以及返回值同时还有方法对象的类路径参数都需要写详细呢 因为java中在不同的包下可以有相同类在不同的类中可能有相同的方法就算是同一个类中也有方法重载所以需要写的具体信息来确定切入点方法。 execution还可以搭配特殊符号使用有些类似正则表达式。现在开始进行简单的演示 例子1 Before(execution(public int com.xzd.aoptest.CalculateImpl.add(..)))这个表示在这个类下通过public int 修饰的所有add方法无论多少个参数。这个 (…) 表示任意参数的类表。 例子2: Before(execution( * com.xzd.aoptest.CalculateImpl.add(..)))这个将修复方法public int替换为***。这位置的*表示任意访问修饰符和返回类型。 例子3 // 可以结合使用其中*位置不同表示不同 Before(execution( * com.xzd.aoptest..(..)))这个位置可以看出有三个*第一个*例子2中已经说明现在说一下后面两个的意义。 第二个*出现在类的地方表示该包下的所有类当然也可以出现在包路径中某个包名用表示此包路径下所有的类。第三个:出现在方法的地方表示该类下的所有方法** 现在通过例子进行演示 //这是一个切面类 通过注解实现创建对象bean Component //通过aspects框架注解告诉系统这个是一个切面类 Aspect public class LogAspects {Before(execution(public int com.xzd...(..)))public void beforeMethod(){System.out.println(调用目标的方法之前调用);}} 然后调用 Testpublic void test1(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring_test.xml);//这里返回的是接口类Calculate calculate (Calculate) applicationContext.getBean(calculateImpl);System.out.println(calculate.add(1,2));System.out.println(calculate.div(10,2));System.out.println(calculate.sub(6,2));System.out.println(calculate.mul(6,2));}看一下结果 argNames 如果不写argNames直接为方法添加参数会如下报错 可以看出会报错。但是对于加强方法是否可以带参数以及形参的意义是什么 但是如下写 Before(value execution(* com.xzd.aoptest.CalculateImpl.add(int,int)) args(c,d) ,argNames c,d) // 可以这样写 可以没有,argNames c,d 但是需有 args(c,d) // Before(value execution(public int com.xzd...(..)) args(c,d))public void beforeMethod(){System.out.println(调用目标的方法之前调用);}可以看出如果使用了argNames “c,d”也就是 args(c,d) 这个表示的是切入点方法传到前置通知方法中的形参是cd那么增强的方法必须带有参数不然就会报错。但是argNames 可以将传递参数的位置变一下比如这样argNames “d,c”而且前置通过方法必须对应的名字是(int dint c)表示前置通知方法中第一个参数是切入点方法的第二个参数。第二个参数是切入点方法的第一个参数。当然默认是和args顺序一样。 **简单说就是 args 决定了通知方法中得到切入点方法后的形参而argNames 决定了在通知方法中形参对应的顺序。默认argNames是和 args 顺序一样的 ** 那么先和要增强的方法参数类型和个数一样试试 Before(value execution(public int com.xzd.aoptest.CalculateImpl.add(int,int)) args(c,d) ,argNames c,d) // 可以这样写 可以没有,argNames c,d 但是需有 args(c,d) // Before(value execution(public int com.xzd...(..)) args(c,d))public void beforeMethod(int c,int d){System.out.println(调用之前的方法的参数 cc d d);System.out.println(调用目标的方法之前调用);}然后看一下结果 可以看出参数也就是切入点传递的参数如果再大胆一些修改一个参数类型是其它类型试试 Before(value execution(public int com.xzd.aoptest.CalculateImpl.add(int,int)) args(c,d) ,argNames c,d) // 可以这样写 可以没有,argNames c,d 但是需有 args(c,d) // Before(value execution(public int com.xzd...(..)) args(c,d))public void beforeMethod(int c,String d){System.out.println(调用之前的方法的参数 cc d d);System.out.println(调用目标的方法之前调用);}看一下结果 然后又做了一个一个实验那就是传递的参数不同也是这样前置通知没有效果从这里可以看出对于前置通知注解 Before如果不使用argNames那么不带参数满足切入点的方法都会调用如果使用了 argNames那么不但要满足好切入点方法而且增强的方法也必须和切入点方法的参数个数和依次类型必须一致不然没有效果参数如果是JoinPoint例外。而且参数在值就是切入点方法传入值。 带JoinPoint这样写 Before(value execution( com.xzd.aoptest.CalculateImpl.add(int,int)) args(c,d) ,argNames joinPoint,c,d)public void beforeMethod(JoinPoint joinPoint,int c ,int d){System.out.println(调用目标的方法之前调用);}JoinPoint具体是什么下面会聊不再这里聊了。 补充 aop无法得到目标对象 使用AOP之后其实是无法得到目标对象的比如 Testpublic void test1(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring_test.xml);//这里返回的是接口类 如果返回实现接口的类CalculateImpl ccalculateImpl (CalculateImpl) applicationContext.getBean(calculateImpl);}可以看出使用了AOP之后无法直接获取被代理的对象了。 因为使用了动态代理所以返回的应该是代理对象而不是被代理对象。 补充—-JoinPoint 如果在通知方法中放入这个参数如下不会报错 Before(value execution(public int com.xzd.aoptest.CalculateImpl.add(int,int))) )public void beforeMethod(JoinPoint point){System.out.println(调用目标的方法之前调用);}看一下这个接口源码解释 可以看出 JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象. 其包含了太多信息现在进行演示 Before(value execution(public int com.xzd.aoptest.CalculateImpl.add(int,int))) )public void beforeMethod(JoinPoint point){System.out.println(JoinPoint 测试方法开始——–);System.out.println(getSignature point.getSignature());System.out.println(getKind point.getKind());System.out.println(getArgs Arrays.toString(point.getArgs()));System.out.println(getTarget point.getTarget());System.out.println(getSourceLocation point.getSourceLocation());System.out.println(getClass point.getClass());System.out.println(JoinPoint 测试方法结束——–);System.out.println(调用目标的方法之前调用);} 看下结果 如果要结合带参数一起使用如下 Before(value execution(* com.xzd.aoptest.CalculateImpl.add(int,int)) args(c,d) ,argNames joinPoint,c,d) // 参数joinPoint所在位置没关系必须一一于argNames对应而且argNames的形参名字也需要一致public void beforeMethod(JoinPoint joinPoint,int c ,int d){System.out.println(调用目标的方法之前调用);}参数joinPoint所在位置必须在第一个位置而且argNames的形参名字也需要一致。虽然没有看源码为什么必须在首位但是想到了肯定是通过反射得到了以不定项参数方法生成形参所以第一个位置默认定义好。 后置通知—After 格式 After(value 切入点表达式或命名切入点,argNames 指定命名切入点方法参数列表参数名字可以有多个用“,”分隔) 这个使用和前置通知使用很相似所以直接演示 After(execution(public int com.xzd...(..)))public void afterMethod(){System.out.println(调用目标的方法之后调用);}然后调用 Testpublic void test1(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring_test.xml);//这里返回的是接口类Calculate calculate (Calculate) applicationContext.getBean(calculateImpl);System.out.println(calculate.add(1,2));System.out.println(calculate.div(10,2));System.out.println(calculate.sub(6,2));System.out.println(calculate.mul(6,2));}也使用execution等关键字这个就不再重复了。而且After的后置通知是无论是异常退出还是正常推出都会被执行。 比如调用除法 Testpublic void test1(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring_test.xml);//这里返回的是接口类Calculate calculate (Calculate) applicationContext.getBean(calculateImpl);System.out.println(calculate.div(1,0));}返回通知—-AfterReturning 这个需要说一下其有注解中的属性值会多一些 //pointcut与value是一样的。如果使用pointcut来声明那么前面声明的value就没用了。 AfterReturning( value切入点表达式或命名切入点,//pointcut切入点表达式或命名切入点,argNames参数列表参数名,returning目标对象的返回值 ) 先来一个简单例子 AfterReturning(value execution(public int com.xzd...(..)))public void afterReturnMethod(){System.out.println(返回通知);}看一下结果 这样写似乎没有问题但是有可能会有这样一个需求那就是切入点的返回值也许在通知中取到这个时候应该如何。 如下操作 // AfterReturning(value execution(public int com.xzd...(..)) args(c,d),returning addresulet) // 如果不使用 argNames 默认是顺序是int c,int d, int addresulet) // (int c,int d, int addresulet)AfterReturning(value execution(public int com.xzd...(..)) args(c,d),returning addresulet,argNames c,addresulet,d)public void afterReturnMethod(int c, int addresulet,int d){System.out.println(addresulet addresulet);System.out.println(返回通知);} 异常通知 —-AfterThrowing //pointcut与value是一样的。如果使用pointcut来声明那么前面声明的value就没用了。 AfterThrowing(value切入点表达式或命名切入点,//pointcut切入点表达式或命名切入点,argNames参数列表参数名,throwing异常对应参数名)很多参数类似所以不再重复演示演示其中一个即可。 AfterThrowing(value execution(public int com.xzd...(..)),throwing throwname)public void affterThrowing(Throwable throwname){System.out.println(异常通知throwname);} 如果正常调用 Testpublic void test1(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring_test.xml);//这里返回的是接口类Calculate calculate (Calculate) applicationContext.getBean(calculateImpl);System.out.println(calculate.div(1,1));}可以看出结果没有异常通知 但是估计来一个错误的 Testpublic void test1(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring_test.xml);//这里返回的是接口类Calculate calculate (Calculate) applicationContext.getBean(calculateImpl);System.out.println(calculate.div(1,0));}环绕通知—Around Around( value切入点表达式或命名切入点,argNames参数列表参数名)这样看似乎最少的参数传递这个涉及到另一个类ProceedingJoinPoint。 ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在Around的切面方法中使用。 ProceedingJoinPoint自然会实现JoinPoint的方法当然也在拓展了方法其也有自己的方法其中最常用的proceed()下面进行简单演示 Around(execution(public int com.xzd...(..)))public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { // 如何结合try-catch-finally 实现所有地方的通知try {System.out.println(切入点方法proceedingJoinPoint.getSignature() 切入点方法参数Arrays.toString(proceedingJoinPoint.getArgs()));System.out.println(环绕通知——————-前置通知);Object resultproceedingJoinPoint.proceed();System.out.println(环绕通知中proceed执行返回的resultresult);result6;System.out.println(环绕通知—————–返回通知);return result;} catch (Exception e) {System.out.println(环绕通知—————异常通知e);throw new RuntimeException(e);} finally {System.out.println(环绕通知—————后置通知);}} }然后通过调用 Testpublic void test1(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring_test.xml);//这里返回的是接口类Calculate calculate (Calculate) applicationContext.getBean(calculateImpl);System.out.println(最后结果—–calculate.div(6,2));}看一下结果 然后再试一下异常通知 Testpublic void test1(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring_test.xml);//这里返回的是接口类Calculate calculate (Calculate) applicationContext.getBean(calculateImpl);System.out.println(最后结果—–calculate.div(6,0));}这个需要注意两点 在环绕通知中通过Object resultproceedingJoinPoint.proceed();表示切入点方法也就是目标方法的执行。 环绕通知方法一般都有返回值毕竟切入点方法人家有返回指定所以无论是否有返回值都有返回值而且两者返回值。因为这个环绕通知方法的return值才是目标方法执行的返回值比如上面案例中6除以2明明是3但是在调用的时候返回时6.所以不写proceed()也会有返回值只是不会调用目标方法而已。
同一个类中环绕通知与其它四个通知的关系 Component //通过aspects框架注解告诉系统这个是一个切面类 Aspect public class LogAspects {// private String addreturn;Before(execution(public int com.xzd...(..)))public void beforeMethod(){System.out.println( Before——调用目标的方法之前调用);}After(execution(public int com.xzd...(..)))public void afterMethod() throws Throwable {System.out.println(After 调用目标的方法之后调用);}AfterReturning(value execution(public int com.xzd...(..)),returning addresulet,argNames addresulet)public void afterReturnMethod(int addresulet ){System.out.println( AfterReturning 返回通知);}AfterThrowing(value execution(public int com.xzd...(..)),throwing throwname)public void affterThrowing(Throwable throwname){System.out.println(AfterThrowing 异常通知throwname);} Around(execution(public int com.xzd...(..)))public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {try {System.out.println(切入点方法proceedingJoinPoint.getSignature() 切入点方法参数Arrays.toString(proceedingJoinPoint.getArgs()));System.out.println(环绕通知——————-前置通知);Object resultproceedingJoinPoint.proceed();System.out.println(环绕通知—————–返回通知);return result;} catch (Exception e) {System.out.println(环绕通知—————异常通知e);throw new RuntimeException(e);} finally {System.out.println(环绕通知—————后置通知);}} }看一下结果: 可以看出似乎环绕通知中的前置通知被直接用Before的前置通知早以外其它的都晚。 但是如果将环绕通知中的 Object resultproceedingJoinPoint.proceed(); 转换为 Object result1;//proceedingJoinPoint.proceed(); 这个可以看出根本就没有调用Before等其它通知为什么 因为环绕通知会将其它四个通知包裹主但是如果不执行proceedingJoinPoint.proceed()方法就不会在依次执行Before等四个通知的方法。 补充其它几种常用注解 重写切入点表达式—-Pointcut 上面演示的时候发现有些切入点是共有的每次都需要写有时候太麻烦了所以有了这个注解现在演示一下 Component //通过aspects框架注解告诉系统这个是一个切面类 Aspect public class LogAspects {Pointcut(execution(public int com.xzd...(..)))public void pointCutMethod(){} // private String addreturn;Before(pointCutMethod())public void beforeMethod(){System.out.println( Before——调用目标的方法之前调用);}After(pointCutMethod())public void afterMethod() throws Throwable {System.out.println(After 调用目标的方法之后调用);} }可以看出Pointcut就是声明了一个公共的切入表达式方便调用。 切面类的优先级—–Order 这个有涉及到一个问题那就是切面类有时候会创建多个但是如果创建多个那先执行谁 还是第一个是日志切面类 Component //通过aspects框架注解告诉系统这个是一个切面类 Aspect public class LogAspects {Pointcut(execution(public int com.xzd...(..)))public void pointCutMethod(){} // private String addreturn;Before(pointCutMethod())public void beforeMethod(){System.out.println( Before——调用目标的方法之前调用);} }再创建一个验证切面类毕竟输入的必须保证是整数。 Component Aspect public class VerifyAspectj {Pointcut(execution(public int com.xzd...(..)))public void pointCutMethod(){} // 不实现具体方法了只是简单的演示Before(pointCutMethod())public void verifyMethod(){System.out.println( Before—–VerifyAspectj -调用目标的方法之前调用);} }然后看一下运行结果 运行顺序和计划的有些出入所以这个时候需要使用Order这个注解。 所有的切面类中Order默认值是最大整数其数值越小表示优先级越高所以可以如下修改 Component //通过aspects框架注解告诉系统这个是一个切面类 Aspect //因为就两个可以使用默认值 Order(101) public class LogAspects {Pointcut(execution(public int com.xzd...(..)))public void pointCutMethod(){} // private String addreturn;Before(pointCutMethod())public void beforeMethod(){System.out.println( Before——调用目标的方法之前调用);} }Component Aspect Order(100) public class VerifyAspectj {Pointcut(execution(public int com.xzd...(..)))public void pointCutMethod(){} // 不实现具体方法了只是简单的演示Before(pointCutMethod())public void verifyMethod(){System.out.println( Before—–VerifyAspectj -调用目标的方法之前调用);} }看一结果 通配符与逻辑运算符 Aspectj支持3种通配符 * 匹配任意字符但它只能匹配上下文中的一个元素… 匹配任意字符可以匹配上下文中的多个元素但在表示类时必须和联合使用而在表示入参时则单独使用。 表示按类型匹配指定类及其子孙类必须跟在类名后面。如cn.framelife.spring.UserService表示UserService类及其子类。 函数支持 支持所有的通配符的函数execution()、within()仅支持 通配符的函数:args()、this()、targ()。虽然这三个函数可以支持 通配符但对于这些函数来说使用和不使用 都是一样的不支持通配符的函数:args、within、target()、annotation()。也就是所有用于注解上的函数都不支持通配符。 Aspectj支持的逻辑运算符 与|| 或! 非
还有一些注解或者注解中的属性within()target()this()annotation()等等就不在演示了。 代码演示–通过XML 配置xml beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdcontext:component-scan base-packagecom.xzd.aoptest/context:component-scan!– 用xml启动aop– aop:config/aop:config /beans可以看下aop:config下的三个标签 现在可以描述一下 标签描述aop:advisor配置通知但是这个与事务有关等聊事务的时候再说aop:pointcut配置切入点表达式优点Pointcut注解的样子aop:aspect配置切面类 然后先一个例子演示一下: Component public class LogAopXML {public void beforeMethod(){System.out.println( Before—–LogAspects -调用目标的方法之前调用);} } 然后配置XML: beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdcontext:component-scan base-packagecom.xzd.aoptest!– 用xml其它aop– aop:config !– 因为通过注解实现注入默认驼峰 也就是xml log类上有注解Component– aop:aspect reflogAopXMLaop:before methodbeforeMethod pointcutexecution(public int com.xzd.
..(..))/aop:before /aop:aspect /aop:config /beans然后看一下运行结果 前置通知—- aop:before method: 配置的是切面类中的通知方法名字 pointcut 或者 pointcut-ref 配置切入点的类 pointcutexecution(和注解配置一样) 或者 pointcut-ref设置的切入点表达式 arg-names配置通知方法的参数这个需要结合execution(和注解配置一样)and args(d,c) 一起使用和注解要求一样不再过多解释来一个完整xml配置 aop:before methodbeforeMethod pointcutexecution(public int com.xzd...(..)) and args(d,c) arg-namesc,d /aop:before不再进行演示了因为和注解演示的很多了。当然也可以添加参数joinPoint和注解中的要求是一致的。 返回通知—aop:after-returning method: 配置的是切面类中的通知方法名字 pointcut 或者 pointcut-ref 配置切入点的类 pointcutexecution(和注解配置一样) 或者 pointcut-ref设置的切入点表达式 returning 表示切入点返回的值然后可以通过arg-names配置将其传递给返回通知方法 arg-names配置通知方法的参数这个需要结合execution(和注解配置一样)and args(d,c) 一起使用和注解要求一样不再过多解释来一个配置 aop:after-returning methodafterReturnMethod pointcutexecution(public int com.xzd...(..)) returningaddresulet arg-namesaddresulet /aop:after-returning 也不再演示结果其要求和注解中对参数值的要求一致。 异常通知—-aop:after-throwing method: 配置的是切面类中的通知方法名字 pointcut 或者 pointcut-ref 配置切入点的类 pointcutexecution(和注解配置一样) 或者 pointcut-ref设置的切入点表达式 throwing 表示切入点抛出的异常然后可以通过arg-names配置将其传递给返回通知方法 arg-names配置通知方法的参数这个需要结合execution(和注解配置一样)and args(d,c) 一起使用和注解要求一样不再过多解释来一个完整配置 aop:after-throwing methodaffterThrowing pointcutexecution(public int com.xzd...(..)) throwingthrromname arg-namesthrromname/aop:after-throwing 也不再演示结果其要求和注解中对参数值的要求一致。 后置通知—-aop:after method: 配置的是切面类中的通知方法名字 pointcut 或者 pointcut-ref 配置切入点的类 pointcutexecution(和注解配置一样) 或者 pointcut-ref设置的切入点表达式 arg-names配置通知方法的参数这个需要结合execution(和注解配置一样)and args(d,c) 一起使用和注解要求一样不再过多解释来一个完整例子 aop:after methodbeforeMethod pointcutexecution(public int com.xzd...(..)) and args(d,c) arg-namesc,d /aop:after也不再演示结果其要求和注解中对参数值的要求一致。 环绕通知—aop:around method: 配置的是切面类中的通知方法名字 pointcut 或者 pointcut-ref 配置切入点的类 pointcutexecution(和注解配置一样) 或者 pointcut-ref设置的切入点表达式 arg-names配置通知方法的参数这个需要结合execution(和注解配置一样)and args(d,c) 一起使用和注解要求一样不再过多解释当然其也会用到ProceedingJoinPoint这个参数和注解一样的。 来一个例子演示 aop:around methodaroundMethod pointcutexecution(public int com.xzd...*(..))/aop:around也不再演示结果其要求和注解中对参数值的要求一致。 对于xml配置AOP了解即可一般的时候更侧重于用注解进行配置。