通过开发日志记录来学习AOP
闲谈
做过Web平台的,基本都清楚,大多数的Web平台都会需要记录接口调用的记录,不要小看它,认为它似乎没什么用,很多的个人习惯就是通过这种方式小成本的被挖掘出来。拿一个小规模的电商平台来说,只要把接口细化分类,我只需要记录某个接口的调用情况,我就知道哪些用户对哪些商品感兴趣,对于页面来说是一个商品点击事件,对于后台来说,就是某个接口某个数据的请求。
我们先了解一下,AOP一般常见场景,AOP的使用,更多用于日志场景、一般被用于日志诊断上下文,比如logback映射辅助上下文,或者用于辅助信息,比如方法执行时间,我们经常会在方法执行前获取一个时间,方法执行后获取一个时间,前者减去后者得到这个方法执行的时间。这些都是常用的手段。比较高级的是用在安防场景上,比如熔断、限流降级、认证授权、请求监控上等等
这次介绍的是,如何通过AOP来小成本的完成一个接口日志的记录,建议刚入行的新人,看完亲手敲一遍。
首先我们设计一个简单的表
DataBaseName
| 字段 | 类似 | 备注 |
|---|---|---|
| id | int | 主键 |
| url | varchar(32) | url接口 |
| name | varchar(32) | 接口名 |
| time | dateTime | 操作时间 |
| user_no | varchar(32) | 用户编号 |
| address | varchar(32) | ip地址 |
| data | json | 具体数据 |
具体的可以根据你们自身的想法给表进行拓展,这里只是为了举例,我就简单设计了。
在注解使用上,我们这次主要用的是@Aspect、@Pointcut、@Around()这三个注解。
@Aspect:把当前类标记成一个切面给容器读取。
@Pointcut:使用与JoinPoint匹配的正则表达式,用于确认是否要执行Advice,是植入Advice的触发条件。举个例子,我把某个接口用Pointcut标记了,当这个接口被使用的时候,就会触发Advice。
@Around():表示使用的是环切,执行方法前,会先执行该注解下的方法内的逻辑,方法执行完后才会执行后续内容。
以下是具体代码:
@Aspect
@Component
public class LogAop {@Autowiredprivate ActionLogService actionLogService;@Pointcut("execution(* xxx.xxx.xxx.*.controller..*.*(..)) && @annotation(io.swagger.annotations.ApiOperation)")public void targetLogAop() {}@Around("targetLogAop()")public Object Interceptor(ProceedingJoinPoint point) {MethodSignature signature = (MethodSignature) point.getSignature();ApiOperation annotation = signature.getMethod().getAnnotation(ApiOperation.class);//获取requestHttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();//获取传参Map<String, String[]> parameterMap = request.getParameterMap();//获取urlString url = request.getRequestURI();//IP地址String address = request.getHeader("X-Forwarded-For");//接口描述String name = annotation.value();//获取当前账号信息User user = UserUtils.getUser();if (!"".equals(operationType)) {UserActionLog log = new UserActionLog();log.setAddress(address);log.setName(name);log.setData(parameterMap);log.setUrl(url);log.setTime(new Date());log.setUserNo(user.getUserNo());//新增记录actionLogService.addUserActionLog(log);}try {//执行后续方法内容return point.proceed();} catch (Throwable e) {e.printStackTrace();throw new BaseRuntimeException(ExceptionMsg.fail(CodeEnum.OPERATION_FAIL, e.getMessage()));}}}
简单讲解一下:
1.使用一个方法记录我们需要对哪些接口进行处理,这里我们可以对接口进行标记的同时,同时还可以标记带某个注解。
@Pointcut("execution(* xxx.xxx.xxx.*.controller..*.*(..)) && @annotation(io.swagger.annotations.ApiOperation)")
public void targetLogAop() {}
该方法,标记了xxx.xxx.xxx.*.controller下的所有接口,并且接口必须标注了@ApiOperation接口才会被包含进去。
2.这个时候就可以在@ApiOperation备注一些信息,到时候可以当作表的name字段数据了。
@ApiOperation(value = "查询商品")
3.将标记的方法放近Around注解里,到时候执行到标记的接口的时候,就会先执行Interceptor方法。
@Around("targetLogAop()")
public Object Interceptor(ProceedingJoinPoint point) {....
}
4.给这个类用上@Aspect、@Component来个注解,前者把当前类标记成一个切面给容器读取,后者把当前类作为一个组件给Spring管理。
@Aspect
@Component
@Slf4j
public class LogAop {....
}
用到这里,如果有人问Spring AOP和AspectJ AOP的区别在哪里?我可以用AspectJ去实现上面的功能吗?
答案其实是可以的。
1、因为Spring AOP只是AOP的部分实现,而AspectJ是AOP的完整实现。用来实现以上的问题绰绰有余。
2、但是如果非要说用法推荐的话,简单使用建议用Spring AOP,因为它只实现部分的结果就是它会比AspectJ在使用上更加简单。
3、Spring AOP 可以看成是Spring容器和AspectJ注解的整合。
4、Spring AOP仅支持代理模式的AOP和仅支持方法级别的Pointcuts。
结束语
这一次的分享到此为此,虽然内容简单,但是对于想入门的同学还是有好处的。如何既能学到知识点,又能获取功能开发经验,对以后开发有帮助呢?那就只有通过需求功能开发,一遍开发一遍介绍知识点,只有这样才是收获最多的。学习aop的方法不止一种,这也只是入门的一种方式,但是无论哪种方式,都避不开亲手敲代码,只能多敲多练习,这个知识点你才可以掌握。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
