zoukankan      html  css  js  c++  java
  • SpringBoot--AOP

     

    Aspect Oriented Programming(AOP):面向切面编程,通过预编译方 式和运行期动态代理实现程序功能的统一维护的一种技术,可以让一组类共享相同的行为,实现解耦。

    Spring AOP:通过JDK的动态代理和CGLIB(Code Generation Librar)实现。

     

    切面(Aspect):Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。

    连接点(Joint point):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。

    切点(Pointcut):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。

    增强(Advice):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。

    引入(Introduction):在不改变一个现有类代码的情况下,为该类添加属性和方法,可以在无需修改现有类的前提下,让它们具有新的行为和状态。其实就是把切面(也就是新方法属性:通知定义的)用到目标类中去。

    目标(target):被通知的对象,就是需要加入额外代码的对象,也就是真正的业务逻辑被组织织入切面。

    织入(Weaving):把切面加入程序代码的过程。切面在指定的连接点被织入到目标对象中,

      在目标对象的生命周期里有多个点可以进行织入:

    • 编译期:切面在目标类编译时被织入,这种方式需要特殊的编译器
    • 类加载期:切面在目标类加载到JVM时被织入,这种方式需要特殊的类加载器,它可以在目标类被引入应用之前增强该目标类的字节码
    • 运行期:切面在应用运行的某个时刻被织入,一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象,Spring AOP就是以这种方式织入切面的。
     1 package org.qa.auto.qaauto.qf.aop;
     2 
     3 import org.aspectj.lang.JoinPoint;
     4 import org.aspectj.lang.ProceedingJoinPoint;
     5 import org.aspectj.lang.annotation.Around;
     6 import org.aspectj.lang.annotation.Aspect;
     7 import org.aspectj.lang.annotation.Before;
     8 import org.aspectj.lang.annotation.Pointcut;
     9 import org.slf4j.Logger;
    10 import org.slf4j.LoggerFactory;
    11 import org.springframework.stereotype.Component;
    12 
    13 import java.lang.reflect.Method;
    14 
    15 /**
    16  * @author qfang
    17  * @date 2019/8/8 23:18
    18  */
    19 @Aspect
    20 @Component
    21 public class QFTestAop {
    22 
    23     private final static Logger logger = LoggerFactory.getLogger(QFTestAop.class);
    24 
    25     @Pointcut("execution(public * org.qa.auto.qaauto.qf.http.service.*.*(..))")
    26 //    @Pointcut("execution(* com.alibaba.fastjson.JSON.parseObject(String))")
    27     public void QFAspect(){}
    28 
    29     @Before("QFAspect()")
    30     public void doBefore(JoinPoint joinPoint){
    31 //        String method1 = joinPoint.getSignature().getName();
    32 //        logger.info("result: " + method1);
    33         logger.info("JoinPoint doBefore start......");
    34         try {
    35             Class clazz = Class.forName("org.apache.http.impl.client.InternalHttpClient");
    36             Method[] methods = clazz.getMethods();
    37             for (Method method : methods){
    38                 logger.warn(method.getName());
    39             }
    40         } catch (ClassNotFoundException e) {
    41             e.printStackTrace();
    42         }
    43         logger.info("JoinPoint doBefore end......");
    44     }
    45 
    46     @Around("QFAspect()")
    47     public Object doAround(ProceedingJoinPoint joinPoint){
    48         logger.info("JoinPoint doAround start......");
    49         try {
    50             Object result = joinPoint.proceed();
    51             logger.info("return result : " + result);
    52             String method = joinPoint.getSignature().getName();
    53 
    54             Class clazz = Class.forName("org.apache.http.impl.client.InternalHttpClient");
    55             Method[] methods = clazz.getMethods();
    56             for (Method md : methods){
    57                 if(md.equals("execute")){
    58                     logger.info("Execute method : " + md);
    59                     return "My Object";
    60                 }
    61             }
    62 
    63             if(method.equals("method1")){
    64                 logger.info("execute method1......");
    65                 result =  "返回自定义报文!!!";
    66             }
    67             logger.info("实际result: " + result);
    68             return result;
    69         } catch (Throwable throwable) {
    70             throwable.printStackTrace();
    71         }
    72         return null;
    73     }
    74 }
    相关注解:

    @Aspect:作用是把当前类标识为一个切面供容器读取:

    @Before(前置通知:在方法开始执行前执行):标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有

    @AfterReturning(返回后通知:在方法返回后执行):后置增强,相当于AfterReturningAdvice,方法正常退出时执行

    @AfterThrowing(异常通知:在抛出异常时执行):异常抛出增强,相当于ThrowsAdvice

    @After(后置通知:在方法执行后执行):final增强,不管是抛出异常或者正常退出都会执行

    @Around(环绕通知:在方法执行前和执行后都会执行):环绕增强,相当于MethodInterceptor

    @DeclareParents:引介增强,相当于IntroductionInterceptor

     执行顺序:around > before > around > after > afterReturning

     切点函数:

    1)execution函数:用于匹配方法执行的连接点

    语法:execution(方法修饰符(可选)  返回类型  方法名  参数  异常模式(可选)) 

     

    参数部分允许使用通配符:

    *  匹配任意字符,但只能匹配一个元素

    .. 匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用

    +  必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类

     

    Example:

    示例中的* chop(..)解读为:

    方法修饰符  无

    返回类型      *匹配任意数量字符,表示返回类型不限

    方法名          chop表示匹配名称为chop的方法

    参数               (..)表示匹配任意数量和类型的输入参数

    异常模式       不限

    更多示例:

    void chop(String,int)

    匹配目标类任意修饰符方法、返回void、方法名chop、带有一个String和一个int型参数的方法

    public void chop(*)

    匹配目标类public修饰、返回void、方法名chop、带有一个任意类型参数的方法

    public String *o*(..)

     匹配目标类public修饰、返回String类型、方法名中带有一个o字符、带有任意数量任意类型参数的方法

    public void *o*(String,..)

     匹配目标类public修饰、返回void、方法名中带有一个o字符、带有任意数量任意类型参数,但第一个参数必须有且为String型的方法

    也可以指定类:

    public void examples.chap03.Horseman.*(..)

    匹配Horseman的public修饰、返回void、不限方法名、带有任意数量任意类型参数的方法

    public void examples.chap03.*man.*(..)

    匹配以man结尾的类中public修饰、返回void、不限方法名、带有任意数量任意类型参数的方法

    指定包:

    public void examples.chap03.*.chop(..)

    匹配examples.chap03包下所有类中public修饰、返回void、方法名chop、带有任意数量任意类型参数的方法

    public void examples..*.chop(..)

    匹配examples.包下和所有子包中的类中public修饰、返回void、方法名chop、带有任意数量任意类型参数的方法
    可以用这些表达式替换StorageAdvisor中的代码并观察效果

    2) @annotation()

    表示标注了指定注解的目标类方法

    例如 @annotation(org.springframework.transaction.annotation.Transactional) 表示标注了@Transactional的方法

    3) args()

    通过目标类方法的参数类型指定切点

    例如 args(String) 表示有且仅有一个String型参数的方法

    4) @args()

    通过目标类参数的对象类型是否标注了指定注解指定切点

    如 @args(org.springframework.stereotype.Service) 表示有且仅有一个标注了@Service的类参数的方法

    5) within()

    通过类名指定切点

    如 with(examples.chap03.Horseman) 表示Horseman的所有方法

    6) target()

    通过类名指定,同时包含所有子类

    如 target(examples.chap03.Horseman)  且Elephantman extends Horseman,则两个类的所有方法都匹配

    7) @within()

    匹配标注了指定注解的类及其所有子类

    如 @within(org.springframework.stereotype.Service) 给Horseman加上@Service标注,则Horseman和Elephantman 的所有方法都匹配

    8) @target()

    所有标注了指定注解的类

    如 @target(org.springframework.stereotype.Service) 表示所有标注了@Service的类的所有方法

    9) this()

    大部分时候和target()相同,区别是this是在运行时生成代理类后,才判断代理类与指定的对象类型是否匹配

    逻辑运算符:表达式可由多个切点函数通过逻辑运算组成

    1. &&

    与操作,求交集,也可以写成and

    例如 execution(* chop(..)) && target(Horseman)  表示Horseman及其子类的chop方法

    2. ||

    或操作,求并集,也可以写成or

    例如 execution(* chop(..)) || args(String)  表示名称为chop的方法或者有一个String型参数的方法

    3. !

    非操作,求反集,也可以写成not

    例如 execution(* chop(..)) and !args(String)  表示名称为chop的方法但是不能是只有一个String型参数的方法

     原文:https://blog.csdn.net/autfish/article/details/51184405

        https://blog.csdn.net/q982151756/article/details/80513340

        https://www.jianshu.com/p/4d22ea402d14

     

  • 相关阅读:
    猴子得到一堆桃,当天吃了一半之后,又多吃了1个。以后每天,猴子都吃了剩余的一半桃子之>后,又多吃一个。在第10天,只剩下1个桃子。输出这堆桃最初有多少个。
    打印9 9乘法表
    尝试实现一个管理系统, 名字和电话号分别用两个列表存储 =======通讯录管理系统======= 1.增加姓名和手机 2.删除姓名 3.修改手机 4.查询所有用户 5.根据姓名查找手机号 6.退出
    求结果
    背景流动
    1
    zuoye
    假期 作业1220
    python1217作业
    pythonzuoye20181212
  • 原文地址:https://www.cnblogs.com/fqfanqi/p/11343293.html
Copyright © 2011-2022 走看看