首先参考
https://blog.csdn.net/qq_38360892/article/details/89498196
https://www.cnblogs.com/jun-ma/p/4844978.html
-场景:sqlApi需要对rest接口进行计量计次,没有找到现成的接口调用次数&流量统计框架,因此考虑使用aop、前/后置通知对接口进行计量计次,前置接口解析token获得调用者信息,后置接口计算调用次数、下行流量
-问题:一般aop是通过包名或类名指定切点类或切点方法的,不够灵活。当我所需要统计流量的接口分散在不同模块时,需要定义多个切面,即使一个模块中不同包下的接口类,也要定义多个切点。
-方案:
1.抽离aop层为功能module,业务module依赖aop层实现aop功能
2.考虑使用注解定义一个方法,使用该注解标注的方法(方法级,实际类级也一样)将被aop层视为切点,并在切点的前置、后置通知中实现计量计次逻辑
-优点:
切点定义灵活:引入依赖,注解指定方法即可定义切点,方便切点的增加删除;不受包、模块的限制
-实现方式: 参考
https://blog.csdn.net/qq_38360892/article/details/89498196
https://www.cnblogs.com/jun-ma/p/4844978.html
1.创建aop模块-statistic-core,引入aop及其它相关依赖
目录结构:
2.创建注解接口WinControllerPointCut:
package com.winning;
import java.lang.annotation.*;
/**
* @author lmx
* @date 2020/9/10 4:41 下午
* 接口切点注解,用于标记需要计量计次的接口
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface WinControllerPointCut {
}
@Rentention设置:
@Retention(RetentionPolicy.SOURCE) 注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,@Retention(RetentionPolicy.RUNTIME) 注解会在class字节码文件中存在,在运行时可以通过反射获取到
此处选择作用与最广的RetentionPolicy.RUNTIME
@Target设置:
@Target(ElementType. FIELD)表示标签只能用来修饰字段、枚举的常量
@Target(ElementType.METHOD)表示标签只能用来修饰方法
@Target(ElementType.TYPE) 标签可用来修饰接口、类、枚举、注解
…
此处由于需要使用细粒度(方法级)的监控,因此选择ElementType.METHOD
3.创建切面类:AopConfig
package com.winning;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
/**
* @author lmx
* @date 2020/9/10 3:57 下午
*/
@Slf4j
@Aspect
@EnableAspectJAutoProxy
@Component
public class AopConfig {
/**
* 定义切点
* 该切点指向某个包,因此要求对应包内只有接口的方法,业务方法请分离到业务层
* 使用@annotation指定切点为 自定义注解接口com.winning.WinControllerPointCut
*/
@Pointcut("@annotation(com.winning.WinControllerPointCut)")
public void winPointCut() {
}
@Async
@Before("winPointCut()")
public void beforeCall(JoinPoint joinPoint) {
//前置通知-业务,入参需要切点方法定义好
ServletRequestAttributes attributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
log.info("before-接口路径:{}", request.getRequestURL().toString());
log.info("before-请求方式:{}", request.getMethod());
log.info("before-类方法:{}" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
log.info("before-请求参数 : {} " + Arrays.toString(joinPoint.getArgs()));
}
@Async
@AfterReturning(pointcut = "winPointCut()", returning = "resp")
public void calcNetflow(Object resp) {
//后置通知-业务,入参需要切点方法定义好
ServletRequestAttributes attributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
log.info("afterReturning-接口路径:{}", request.getRequestURL().toString());
}
}
4.mvn install打包
-使用
1.业务module-sqlApi的pom中引入statistic-core:
<dependency>
<groupId>com.winning</groupId>
<artifactId>statistic-core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2.使用自定义注解标注到接口方法上,即可将接口定义为切点。
3.启动sqlApi,测试验证-接口被调用时,就会进入切面中定义的切点前置&后置通知