AOP使用示例:日志采集功能
背景: 目的是为了优化CalledListRequest接口,深入了解后发现这个接口写的不是那么好,循环调用某个接口。导致某些简单的查询被反复执行。从而效率。然后这个接口涉及到的业务逻辑太过于复杂,没敢直接改。而是新写了个接口取代它。但是为了做更充分的测试。先线上采集请求参数。然后进行测试。最后在发布上线是最好的方式。
功能以及原理介绍
为了收集线上这个接口(CalledListRequest)的请求参数。
原理:写一个方法,将传递过来的参数全部插入到数据库的日志表里面。
但是为了减少侵入性(就是不改变原有接口的实现代码)。我这里使用了AOP切入的方式。同时配合apollo做了一个开关(控制什么时候开始收集,什么时候关闭收集)
主要的一个技能点就是对AOP的应用了,之前其实没有实际工作去应用到AOP,这一次算是个机会了
其实特别简单,直接的核心代码就好了。没有复杂的东西
核心代码
package com.centanet.bizcom.config.log;
import com.alibaba.fastjson.JSON;
import com.centanet.bizcom.config.apollo.ApolloConfig;
import com.centanet.bizcom.config.ddb.MultiTenantChanger;
import com.centanet.bizcom.mapper.BizMapper;
import com.centanet.bizcom.model.entity.LogCollection;
import com.centanet.bizcom.util.CityHelper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
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.Date;
/**
* 该类的功能是为了收集日志
* 方便切换接口时使用
* @Author: wbdengtt
* @Date: 2020/10/13 14:58
*/
//声明切面
@Aspect
// 交给Spring管理bean
@Component
public class LogCollectAspect {
// 注入logCollection 这个就是一个简单实体entity。
@Autowired
private LogCollection logCollection;
// 这是将实体存到数据库的mapper
@Autowired
private BizMapper bizMapper;
// 拦截CalledController.calledListRequest方法。通过这个配置。可以拦截更多东西,这个规则相信的可以看下面的参考文章
@Pointcut("execution(* com.centanet.bizcom.controller.CalledController.calledListRequest(..))")
public void myPointCut() {
// 这个其实就是一个切点,不需要方法内容
}
// 这个是具体实现拦截参数,并将参数日志写入到数据库的方法
@Before("myPointCut()")
public void logCollect(JoinPoint joinPoint) {
// 这个是在apoll配置的开关(就是一个String变量)。如果开了才进行下面的拦截。
boolean isLogCollect = "true".equalsIgnoreCase(ApolloConfig.getWebValue(CityHelper.getCityCode(),"isLogCollectionOpen"))
&& ApolloConfig.getWebValue(CityHelper.getCityCode(),"logCollectCity").contains(CityHelper.getCityen());
if (isLogCollect) {
// 设置logCollection的日期字段
logCollection.setRowDate(new Date());
// 获取当前HttpServletRequest 对象 这个是为了拿到各种我需要的信息。关于HttpServletRequest 下面有提供参考链接看相信的介绍
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
//设置logCollection的实体字段,这里是请求类型.城市
logCollection.setMethodName(request.getMethod()+"."+CityHelper.getCityen());
//request.getQueryString() 只能拿到get请求的参数。如果是post请求,得通过joinPoint才能拿到参数(这个不需要手动声明,应该是SpringAOP哪里给自动注入了)
logCollection.setMessage(JSON.toJSONString(joinPoint.getArgs()));
if (logCollection.getMessage() ==null){
logCollection.setMessage("没能拿到参数");
}
// request.getRequestURI()获取方法名
logCollection.setFullName(request.getRequestURI());
// 写入数据库 MultiTenantChanger是因为我有多个数据库,但是这里的操作其实就是讲实体装入数据库
MultiTenantChanger.setDataSourceType(CityHelper.getCityCode()+MultiTenantChanger.CENTA_BIZ);
bizMapper.insertLogCollection(logCollection);
MultiTenantChanger.removeRouteKey();
}
}
}
我给代码加了许多注释。应该是比较好明白的
参考文章:
Joinpoint:
https://blog.csdn.net/qq_15037231/article/details/80624064
HttpServletRequest相关:
https://blog.csdn.net/cold___play/article/details/100920952
execution规则:
https://blog.csdn.net/weixin_39209728/article/details/83752754
AOP简介(这篇是我自己以前写的)
https://blog.csdn.net/m0_37628958/article/details/106201011