Spring Cloud Alibaba-AOP(十九)

简介

AOP(面向切面编程),做为OOP(面向对象编程)的补充,用于处理哪些业务无关的,例如鉴权,日志等公共逻辑,将之抽取封装成一个可重用的模块(切面),减小代码重复,下降耦合,提升系统可维护性。java

方式

静态代理

编译阶段将AspectJ(切面)织入到Java字节码生成AOP代理类spring

动态代理

运行阶段在内存中临时生产一个AOP对象且在特定的切点作了加强处理编程

  • JDK动态代理(基于接口)
  • CGLIB动态代理(基于继承)

术语

  • Advice(通知/加强):切面须要作的具体工做
  • Join point(链接点):容许使用通知的地方
  • Poincut(切点):执行的位置
  • Aspect(切面):通知和切点的结合
  • Introduction(引入):切面定义的属性方法应用到目标类
  • target(目标):被通知的对象
  • Weaving(织入):把切面加入程序代码的过程

经常使用的加强类型

  • 前置通知(before):在某链接点以前执行的通知,但这个通知不能阻止链接点前的执行(除非抛出异常)
  • 返回后通知(afterReturning):在某链接点正常完成后执行的通知
  • 抛出异常后通知(afterThrowing):在方法抛出异常退出时执行的通知
  • 后通知(after):当某链接点退出的时候执行的通知
  • 环绕通知(around):包围一个链接点通知

执行顺序

  • @Order(1):越小越先执行
  • around->before->around->after->afterReturning
  • 橙色:@Order(1),绿色:@Order(2)

Springboot引入AOP

  • 加依赖
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
复制代码
  • 写注解
复制代码
  • 写配置
复制代码

Introduction

package com.virgo.user.auto;

import com.virgo.user.service.TestService;
import com.virgo.user.service.TestServiceImpl;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:00
 */
@Aspect
@Component
public class IntroductionAop {
    @DeclareParents(value = "com.virgo.user..service..*", defaultImpl = TestServiceImpl.class)
    public TestService testService;
}

package com.virgo.user.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:02
 */
@Service
@Slf4j
public class TestServiceImpl implements TestService{
    @Override
    public void test() {
        log.info("all can use");
    }
}


...
        // CommonService使用TestService
        TestService testService = (TestService)commonServiceImpl;
        testService.test();
...
复制代码

顺序

  • 代码
package com.virgo.user.auto;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:29
 */
@Slf4j
@Aspect
@Component
@Order(1)
public class TestAopOrder1 {
    @Pointcut("execution(* com.virgo.user.service.*.*(..))")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void begin() {
        log.info("2:{}","before");
    }

    @After("pointcut()")
    public void commit() {
        log.info("9:{}","after");
    }

    @AfterReturning("pointcut()")
    public void afterReturning(JoinPoint joinPoint) {
        log.info("10:{}","afterReturning");
    }

    @AfterThrowing("pointcut()")
    public void afterThrowing() {
        log.info("afterThrowing");
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            log.info("1:{}","around");
            return joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        } finally {
            log.info("8:{}","around");
        }
    }
}
package com.virgo.user.auto;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:11
 */
@Slf4j
@Aspect
@Component
@Order(2)
public class TestAopOrder2 {
    @Pointcut("execution(* com.virgo.user.service.*.*(..))")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void begin() {
        log.info("4:{}","before");
    }

    @After("pointcut()")
    public void commit() {
        log.info("6:{}","after");
    }

    @AfterReturning("pointcut()")
    public void afterReturning(JoinPoint joinPoint) {
        log.info("7:{}","afterReturning");
    }

    @AfterThrowing("pointcut()")
    public void afterThrowing() {
        log.info("afterThrowing");
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            log.info("3:{}","around");
            return joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        } finally {
            log.info("5:{}","around");
        }
    }
}
复制代码
  • 效果

注解生效AOP

注解

  • @Target:注解的做用目标
    • ElementType.TYPE:容许被修饰的注解做用在类、接口和枚举上
    • ElementType.FIELD:容许做用在属性字段上
    • ElementType.METHOD:容许做用在方法上
    • ElementType.PARAMETER:容许做用在方法参数上
    • ElementType.CONSTRUCTOR:容许做用在构造器上
    • ElementType.LOCAL_VARIABLE:容许做用在本地局部变量上
    • ElementType.ANNOTATION_TYPE:容许做用在注解上
    • ElementType.PACKAGE:容许做用在包上
  • @Retention:注解的生命周期
    • RetentionPolicy.SOURCE:Annotations are to be discarded by the compiler.(编译期可见,不会写入 class 文件)
    • RetentionPolicy.CLASS:Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. This is the default behavior.(写入 class 文件,类加载丢弃)
    • RetentionPolicy.RUNTIME:Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.(永久保存,能够反射获取)
  • @Documented:注解是否应当被包含在 JavaDoc 文档中
  • @Inherited:是否容许子类继承该注解

AOP

  • 代码
package com.virgo.user.auto;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:39
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAop {
    String value() default "";
}

package com.virgo.user.auto;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:53
 */
@Slf4j
@Aspect
@Component
@Order(1)
public class TestAnnotationAop {
    @Pointcut(value = "@annotation(logAop)", argNames = "logAop")
    public void pointcut(LogAop logAop) {
    }

    @Around(value = "pointcut(logAop)", argNames = "joinPoint,logAop")
    public Object around(ProceedingJoinPoint joinPoint,LogAop logAop) throws Throwable {
        try {
            log.info(logAop.value());
            return joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        } finally {
            log.info("");
        }
    }
}
复制代码
  • 效果(方法加注释@LogAop("测试Annotation"))

execution

execution(* com.virgo.user.service...(..))bash

  • 第一个*:任意的返回值
  • com.virgo.user.service:包名
  • .. :当前包及其子包
  • *:全部类
  • .*(..) 表示任何方法,括号表明参数 .. 表示任意参数
相关文章
相关标签/搜索