• 三(二)、AOP配置


    一、AOP的配置(注解)

    步骤一、导入jar包:

    处理那5个jar包之外,还需要导入:

    • aopalliance
    • aspectjweaver
    • spring-aop
    • spring-aspects

    步骤二、在配置文件中加入aop、context的命名空间

    步骤三分为基于注解方式配置AOP和xml方式配置aop;

    基于注解方式(本篇)

    ①在配置文件中加入如下配置;

    1 <!-- 使AspjectJ注释起作用,自动匹配的类生成代理对象 -->
    2  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    ②把横切关注点的代码都加入到切面的类中,

    ③切面首先是一个IOC中的bean,即加@Conponent注释

    ④切面需要加入@Aspect注释

    ⑤在类中声明各种通知:

    • @Before:前置通知,在方法执行前执行;
    • @After:后置通知,在方法执行后执行
    • @AfterRunning:返回通知,在方法返回结果后执行

    • @Afterthrowing:异常通知之后

    • @Around:环绕通知

    二、AOP常用通知:

    • @Before:前置通知,在方法执行前执行;
        @Before("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )") // 作用于接口中的所有方法
        public void beforeMethod(JoinPoint joinPoint) {
            String method = joinPoint.getSignature().getName();// 方法的签名
            List<Object> args = Arrays.asList(joinPoint.getArgs());// 方法的参数
            System.out.println("the method " + method + " begins with" + args);
        }
    • @After:后置通知,在方法执行后执行,在后置通知中,不能访问目标方法执行的结果,如果有异常也执行,通知在异常之前;
    1     @After("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )")
    2     public void afterMethod(JoinPoint joinPoint) {
    3         String method = joinPoint.getSignature().getName();
    4         List<Object> args = Arrays.asList(joinPoint.getArgs());
    5         System.out.println("the method " + method + " is end to " + args);
    6     }
    • @AfterRunning:返回通知,在方法返回结果后执行,可以访问到返回值;

    1     @AfterReturning(value = "execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.add(int, int) )", returning = "result")
    2     public void afterReturn(JoinPoint joinPoint, Object result) {
    3         String method = joinPoint.getSignature().getName();
    4         System.out.println("the method " + method + " is end with " + result);
    5     }
    • @Afterthrowing:异常通知之后,可以访问到异常,并且可以指定异常类型,只有符合该异常类型时才被执行

    1     @AfterThrowing(value = "execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.add(int, int) )", throwing = "ex")
    2     public void afterThrowing(JoinPoint joinPoint, Object ex) {
    3         String method = joinPoint.getSignature().getName();
    4         System.out.println("the method " + method + " occured exception: " + ex);
    5     }
    • @Around:环绕通知;

      环绕通知类似动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行日志方法 且必须有返回值,返回值是目标方法的返回值

     1     @Around("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.add(int, int) )")
     2     public Object aroundMethod(ProceedingJoinPoint point) {
     3         Object result = null;
     4         String method = point.getSignature().getName();
     5         // 执行目标方法
     6         try {
     7             // 前置通知
     8             System.out.println("the method " + method + " is begin with " + Arrays.asList(point.getArgs()));
     9             result = point.proceed();
    10             // 返回通知
    11             System.out.println("the method " + method + " is end to " + result);
    12         } catch (Throwable e) {
    13             // TODO Auto-generated catch block
    14             System.out.println("the method " + method + " occured exception: " + e);
    15             throw new RuntimeException(e);
    16         }
    17         System.out.println("the method " + method + " ends");
    18 
    19         return 100;
    20     }

    三、切点表达式

    表达式

    1 execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

    这里问号表示当前项可以有也可以没有,其中各项的语义如下:

    • modifiers-pattern:方法的可见性,如public,protected;
    • ret-type-pattern:方法的返回值类型,如int,void等;
    • declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;
    • name-pattern:方法名类型,如buisinessService();
    • param-pattern:方法的参数类型,如java.lang.String;
    • throws-pattern:方法抛出的异常类型,如java.lang.Exception;

    举例说明:

    //    @Before("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.add(int, int) )")// 作用于接口中的add方法
    //     @Before("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )") // 作用于接口中的所有方法 (所有方法是指public int类型的)
    //    @Before("execution(* ixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )") // 第一个* 表示:任意修饰符和任意返回值,第二个*代码任意参数为(int,int)方法
    //    @Before("execution( public * ixiuming.spring.aop.impl.ArithmeticCaculator.*(..) )") // 第二个*代表任意方法;..代表任意个数的参数,即所有公有方法
    //    @Before("execution( public double ixiuming.spring.aop.impl.ArithmeticCaculator.*(double.) )") // 返回所有double的第一个参数为double的public的方法

     @Pointcut

    使用@Pointcut 来声明切入点表达式,后面的其他通知直接使用方法名来引用当前的切入点表达式;如下代码,前置通知使用了方法名为declareJoinPointExpress来引用切点表达式;

    这样做的好处是,可以统一管理切点表达式;

     1     @Pointcut("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(..))")
     2     public void declareJoinPointExpress() {
     3 
     4     }
     5 
     6 //声明该方法是一个前置通知:在目标方法之前执行
     7     @Before("declareJoinPointExpress()")
     8     public void beforeMethod(JoinPoint joinPoint) {
     9         String method = joinPoint.getSignature().getName();
    10         List<Object> args = Arrays.asList(joinPoint.getArgs());
    11         System.out.println("the method " + method + " begins with" + args);
    12     }

    四、实例说明AOP配置:

    以实现三(一)中的 为ArithmeticCaculator添加 各方法 执行前 和计算结果后的日志的AOP方案为实例;

    步骤一、为ArithmeticCaculatorImpl类添加@Component 注解 来表示 该组件需要被sping容器管理

     1 package lixiuming.spring.aop.impl;
     2 
     3 import org.springframework.stereotype.Component;
     4 
     5 @Component
     6 public class ArithmeticCaculatorImpl2 implements ArithmeticCaculator {
     7 
     8     @Override
     9     public int add(int i, int j) {
    10         int result = i+j;
    11         return result;
    12     }
    13 
    14     @Override
    15     public int sub(int i, int j) {
    16         int result = i-j;
    17         return result;
    18     }
    19 
    20     @Override
    21     public int mul(int i, int j) {
    22         int result = i*j;
    23         return result;
    24     }
    25 
    26     @Override
    27     public int div(int i, int j) {
    28         int result = i/j;
    29         return result;
    30     }
    31 
    32 }
    View Code

    步骤二、需要添加一个切面:

    关于切面声明的说明:

    • 切面需要放置在spring 容器中;所以首先需要一个@Component注解
    • 声明一个切面用注解 @Aspect;

    为实现上述实例,需要添加一个前置通知和后置通知;前置通知即,在目标方法执行之前执行;后置通知,即在目标方法执行后执行,无论是否发生异常。

     1 package lixiuming.spring.aop.impl;
     2 
     3 import java.util.Arrays;
     4 import java.util.List;
     5 
     6 import org.aspectj.lang.JoinPoint;
     7 import org.aspectj.lang.annotation.After;
     8 import org.aspectj.lang.annotation.Aspect;
     9 import org.aspectj.lang.annotation.Before;
    10 import org.springframework.stereotype.Component;
    11 
    12 //把这个类声明为一个切面,需要把该类放入到IOC容器中,再声明为一个切面
    13 @Aspect
    14 @Component
    15 public class LoggingAspect {
    16     // 声明该方法是一个前置通知:在目标方法之前执行
    18     @Before("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )") // 作用于接口中的所有方法
    22     public void beforeMethod(JoinPoint joinPoint) {
    23         String method = joinPoint.getSignature().getName();// 方法的签名
    24         List<Object> args = Arrays.asList(joinPoint.getArgs());// 方法的参数
    25         System.out.println("the method " + method + " begins with" + args);
    26     }
    27 
    28     // 声明后置通知:在目标方法执行后(无论是否发生异常)执行的通知
    29     // 在后置通知中,不能访问目标方法执行的结果,需要在返回通知里面访问
    30     @After("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )")
    31     public void afterMethod(JoinPoint joinPoint) {
    32         String method = joinPoint.getSignature().getName();
    33         List<Object> args = Arrays.asList(joinPoint.getArgs());
    34         System.out.println("the method " + method + " is end to " + args);
    35     }
    36 
    37 }

     步骤三、配置文件:引入了context和aop的命名空间

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xmlns:aop="http://www.springframework.org/schema/aop"
     5     xmlns:context="http://www.springframework.org/schema/context"
     6     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     7         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
     8         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
     9 
    10 <context:component-scan base-package="lixiuming.spring.aop.impl"/>
    11 <!-- 使AspjectJ注释起作用,自动匹配的类生成代理对象 -->
    12 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    13 </beans>

    使用main方法测试:

     1 public static void main(String[] args) {
     2         ApplicationContext cxt = new ClassPathXmlApplicationContext("ApplicationContext.xml");
     3         ArithmeticCaculator arithmeticCaculator = cxt.getBean(ArithmeticCaculator.class);
     4 
     5         int result = arithmeticCaculator.add(1, 2);
     6         System.out.println("-->" + result);
     7 
     8         int result1 = arithmeticCaculator.div(4, 2);
     9         System.out.println("-->" + result1);
    10 
    11         int result2 = arithmeticCaculator.mul(4, 2);
    12         System.out.println("-->" + result2);
    13 
    14         int result3 = arithmeticCaculator.sub(4, 2);
    15         System.out.println("-->" + result3);
    16 
    17     }

    测试运行结果:

    the method add begins with[1, 2]

    the method add is end to [1, 2]

    -->3

    the method div begins with[4, 2]

    the method div is end to [4, 2]

    -->2

    the method mul begins with[4, 2]

    the method mul is end to [4, 2]

    -->8

    the method sub begins with[4, 2]

    the method sub is end to [4, 2]

    -->2

    步骤二中除了使用前置和后置通知,还可以使用环绕通知来实现上述功能;

    代码如下:

     1 package lixiuming.spring.aop.impl;
     2 
     3 import java.util.Arrays;
     4 
     5 import org.aspectj.lang.ProceedingJoinPoint;
     6 import org.aspectj.lang.annotation.Around;
     7 import org.aspectj.lang.annotation.Aspect;
     8 import org.aspectj.lang.annotation.Pointcut;
     9 import org.springframework.stereotype.Component;
    10 
    11 //把这个类声明为一个切面,需要把该类放入到IOC容器中
    12 @Aspect
    13 @Component
    14 public class LoggingAspect {
    15 
    16     // 定义一个方法,用于声明切入点表达式,一般该方法中不需要其他的代码
    17     // 使用@Pointcut 来声明切入点表达式,
    18     // 后面的其他通知直接使用方法名来引用当前的切入点表达式
    19     @Pointcut("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(..))")
    20     public void declareJoinPointExpress() {
    21 
    22     }
    23 
    24     /**
    25      * 环绕通知需要携带ProceedingJoinPoint类型的参数
    26      * 环绕通知类似动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行日志方法 且必须有返回值,返回值是目标方法的返回值
    27      */
    28     @Around("declareJoinPointExpress()")
    29     public Object aroundMethod(ProceedingJoinPoint point) {
    30         Object result = null;
    31         String method = point.getSignature().getName();
    32         // 执行目标方法
    33         try {
    34             // 前置通知
    35             System.out.println("the method " + method + " is begin with " + Arrays.asList(point.getArgs()));
    36             result = point.proceed();
    37             // 后置通知
    38             System.out.println("the method " + method + " is end to " + Arrays.asList(point.getArgs()));
    39         } catch (Throwable e) {
    40             // TODO Auto-generated catch block
    41             System.out.println("the method " + method + " occured exception: " + e);
    42             throw new RuntimeException(e);
    43         }
    44 
    45         return result;
    46     }
    47 }

     五、切面的优先级

    使用@Order(index)指定执行顺序的优先级,index为数字,index越小,优先级越高;@Order位置为放置在@Aspect前面;代码如下:

    @Order(1)//执行顺序的优先级
    @Aspect
    @Component
    //验证通知
    public class VlidationAspect {
        @Before("LoggingAspect.declareJoinPointExpress()")
        public void validationArgs(JoinPoint jointPoint){
            System.out.println("-->validation:"+Arrays.asList(jointPoint.getArgs()));
        }
        
    
    }

    六、xml方式配置AOP

    ArithmeticCaculator 不变;ArithmeticCaculatorImpl移除@Component;

    LoggingAspect:

     1 package lixiuming.spring.aop.impl2;
     2 
     3 import java.util.Arrays;
     4 import java.util.List;
     5 
     6 import org.aspectj.lang.JoinPoint;
     7 import org.aspectj.lang.ProceedingJoinPoint;
     8 import org.aspectj.lang.annotation.After;
     9 import org.aspectj.lang.annotation.AfterReturning;
    10 import org.aspectj.lang.annotation.AfterThrowing;
    11 import org.aspectj.lang.annotation.Around;
    12 import org.aspectj.lang.annotation.Aspect;
    13 import org.aspectj.lang.annotation.Before;
    14 import org.aspectj.lang.annotation.Pointcut;
    15 import org.springframework.stereotype.Component;
    16 
    17 public class LoggingAspect {
    18 
    19     public void beforeMethod(JoinPoint joinPoint){
    20         String method = joinPoint.getSignature().getName();
    21         List<Object> args = Arrays.asList(joinPoint.getArgs());    
    22         System.out.println("the method "+method+" begins with"+args);
    23     }
    24 
    25     public void afterMethod(JoinPoint joinPoint){
    26         String method =  joinPoint.getSignature().getName();
    27         List<Object> args = Arrays.asList(joinPoint.getArgs());
    28         System.out.println("the method "+method+" is end to "+args);
    29     }
    30     
    31     /**
    32      *在方法正常结束后执行的代码
    33      *返回通知是可以访问到方法的返回值
    34      */
    35     public void afterReturn(JoinPoint joinPoint,Object result){
    36         String method = joinPoint.getSignature().getName();
    37         System.out.println("the method "+method+" is end with " +result);
    38     }
    39 
    40     public void afterThrowing(JoinPoint joinPoint,Object ex){
    41         String method = joinPoint.getSignature().getName();
    42         System.out.println("the method "+method+" occured exception: " + ex);
    43     }
    44     
    45     public Object aroundMethod(ProceedingJoinPoint point){
    46         Object result = null;
    47         String method = point.getSignature().getName();
    48         //执行目标方法
    49         try {
    50             //前置通知
    51             System.out.println("the method "+method+" is begin with "+Arrays.asList(point.getArgs()));
    52             result = point.proceed();
    53             //返回通知
    54             System.out.println("the method "+method+" is end to "+ result);
    55         } catch (Throwable e) {
    56             // TODO Auto-generated catch block
    57             System.out.println("the method "+method+" occured exception: " + e);
    58             throw new RuntimeException(e);
    59         }
    60         System.out.println("the method "+method+" ends");
    61 
    62         return 100;
    63     }
    64 }
    VlidationAspect:
     1 package lixiuming.spring.aop.impl2;
     2 
     3 import java.util.Arrays;
     4 
     5 import org.aspectj.lang.JoinPoint;
     6 import org.aspectj.lang.annotation.Aspect;
     7 import org.aspectj.lang.annotation.Before;
     8 import org.springframework.core.annotation.Order;
     9 import org.springframework.stereotype.Component;
    10 //验证通知
    11 public class VlidationAspect {
    12     public void validationArgs(JoinPoint jointPoint){
    13         System.out.println("-->validation:"+Arrays.asList(jointPoint.getArgs()));
    14     }
    15     
    16 
    17 }

    配置文件:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xmlns:aop="http://www.springframework.org/schema/aop"
     5     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     6         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
     7 
     8 <!-- 配置bean -->
     9 <bean id="aop" class="lixiuming.spring.aop.impl2.ArithmeticCaculatorImpl2"></bean>
    10 <!-- 配置切面的bean -->
    11 <bean id="LoggingAspect" class="lixiuming.spring.aop.impl2.LoggingAspect"></bean>
    12 <bean id="VlidationAspect" class="lixiuming.spring.aop.impl2.VlidationAspect"></bean>
    13 
    14 <!-- 配置AOP -->
    15 <aop:config>
    16     <!-- 配置切面表达式 -->
    17     <aop:pointcut expression="execution(* lixiuming.spring.aop.impl2.ArithmeticCaculator.*(int,int))" id="pointcut"/>
    18     <!-- 配置切面及通知 -->
    19     <aop:aspect ref="LoggingAspect" order="2">
    20         <aop:before method="beforeMethod" pointcut-ref="pointcut"/>
    21         <aop:after method="afterMethod" pointcut-ref="pointcut"/>
    22         <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>
    23         <aop:after-returning method="afterReturn" pointcut-ref="pointcut" returning="result"/>
    24         <aop:around method="aroundMethod" pointcut-ref="pointcut"/>
    25      </aop:aspect>
    26      
    27      <aop:aspect ref="VlidationAspect" order="1">
    28          <aop:before method="validationArgs" pointcut-ref="pointcut"/>
    29       </aop:aspect>
    30 </aop:config>
    31 </beans>
    我从来不相信什么懒洋洋的自由。我向往的自由是通过勤奋和努力实现的更广阔的人生。 我要做一个自由又自律的人,靠势必实现的决心认真地活着。
  • 相关阅读:
    ANR----以及如何定位是前端问题还是后台问题?
    一个App或者web端,你怎么展开测试
    创业性公司,你以什么方式来进行对真机的成本降低 ?
    判断查找IP的两种方法
    接口测试(四)总结及小技巧笔记
    接口测试 (三)功能分类及配置文件引入
    接口测试(二) 优化项目分层及cookies值带入
    接口测试模块完整版
    接口测试入门
    unittest框架(惨不忍睹低配版)
  • 原文地址:https://www.cnblogs.com/lixiuming521125/p/15415582.html
Copyright © 2020-2023  润新知