转载

Spring Cloud Alibaba-AOP(十九)

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

方式

静态代理

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

动态代理

运行阶段 在内存中临时生产一个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)
Spring Cloud Alibaba-AOP(十九)

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");
        }
    }
}
复制代码
  • 效果
Spring Cloud Alibaba-AOP(十九)

注解生效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"))
    Spring Cloud Alibaba-AOP(十九)
原文  https://juejin.im/post/5db105b4e51d4529e5391fbb
正文到此结束
Loading...