SpringCloud应用篇之AOP实现日志功能

前面针对AOP的使用姿势和一些疑问进行了说明,这一篇则从应用的角度出发,看下AOP可以实现些什么样的效果

I. AOP实现日志拦截

1. 背景及目标

对于后端服务而言,一个日常的需求就是需要记录一些关键方法调用历史情况,用于分析接口的响应、问题定位排查等,属于比较常见的场景了

因此,我们希望可以针对某些接口,知道传入的参数时什么,谁调用的,返回了啥,耗时多少这些基本信息。显然这些属于公用的普适性需求,与方法本身的业务无关,如果直接在每个方法内部中加这个逻辑,就比较恶心了;为了最少的倾入性和通用性,正好可以使用AOP来实现这么一个功能

  • 拦截目标方法的执行

  • 打印请求参数,返回结果和执行时间到日志

2. 实现

这个属于比较aop的简单使用场景,因为需要知道返回结果,所有选择 around 或者 afterReturning advice;此外需要统计方法执行耗时,这样就只能选中 around 了

首先我们支持自定义注解方式,先定义一个注解,只要这个方法上有这个注解,就拦截

1
2
3
4
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnoDot {
}

其次,如果想更通用拦截指定包路径下的方法,可以如下定义PointCut;注意下面语句中的||表示或,只有有一个满足即可

1
2
3
@Pointcut("execution(public * com.git.hui.boot.aop.demo.*.*(..)) || @annotation(AnoDot)")
public void pointcut() {
}

接着就是我们的advice实现了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Around(value = "pointcut()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object res = null;
String req = null;
long start = System.currentTimeMillis();
try {
req = buildReqLog(proceedingJoinPoint);
res = proceedingJoinPoint.proceed();
return res;
} catch (Throwable e) {
res = "Un-Expect-Error";
throw e;
} finally {
long end = System.currentTimeMillis();
System.out.println(req + "" + JSON.toJSONString(res) + SPLIT_SYMBOL + (end - start));
}
}


private String buildReqLog(ProceedingJoinPoint joinPoint) {
// 目标对象
Object target = joinPoint.getTarget();
// 执行的方法
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
// 请求参数
Object[] args = joinPoint.getArgs();

StringBuilder builder = new StringBuilder(target.getClass().getName());
builder.append(SPLIT_SYMBOL).append(method.getName()).append(SPLIT_SYMBOL);
for (Object arg : args) {
builder.append(JSON.toJSONString(arg)).append(",");
}
return builder.substring(0, builder.length() - 1) + SPLIT_SYMBOL;
}

3. 测试

添加下测试代码,我们先创建两个bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 这个bean下的方法,演示注解拦截
// com.git.hui.boot.aop.anodemo.AnoDemo
@Component
public class AnoDemo {

@AnoDot
public String gen(String ans) {
return UUID.randomUUID() + "<>" + ans;
}
}


// 这个bean下的方法,演示正则方式的拦截
// 注意前面的参数为..,表示任意参数类型和个数的方法都会拦截
// com.git.hui.boot.aop.demo.PrintDemo
@Component
public class PrintDemo {

public String genRand(int seed, String suffix) {
return seed + UUID.randomUUID().toString() + suffix;
}
}

启动类如下

1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class Application {

public Application(PrintDemo printDemo, AnoDemo anoDemo) {
System.out.println(printDemo.genRand(10, "--一灰灰Blog"));
System.out.println(anoDemo.gen("!23"));
}

public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}

输出结果

1
2
3
4
com.git.hui.boot.aop.demo.PrintDemo|genRand|10,"--一灰灰Blog"|"10521195c0-3c2a-41d0-82f5-a41afad066b0--一灰灰Blog"|240
10521195c0-3c2a-41d0-82f5-a41afad066b0--一灰灰Blog
com.git.hui.boot.aop.anodemo.AnoDemo|gen|"!23"|"1e3438fe-e31f-4f75-8405-4ff7494f9c9c<>!23"|26
1e3438fe-e31f-4f75-8405-4ff7494f9c9c<>!23

II. 其他

0. 项目

  • 工程:spring-boot-demo

  • 项目: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/011-aop-logaspect

1. 一灰灰Blog

  • 一灰灰Blog个人博客 https://blog.hhui.top

  • 一灰灰Blog-Spring专题博客 http://spring.hhui.top

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

2. 声明

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

  • 微博地址: 小灰灰Blog

  • QQ: 一灰灰/3302797840

3. 扫描关注

一灰灰blog

知识星球

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一灰灰blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值