使用AOP实现一个接口监视器

使用AOP实现一个接口监视器

一、背景

      在接口调试的过程中,很多时候会出现接口bug,在生产环境很难找到具体接口的参数,返回值,以及异常信息,此时我们就需要一个接口日志监听器,来保证我们接口调试过程中的便利性

二、开发思路

      编写接口信息监听器,我们可以采用filter与spring所提供的AOP,AOP相比filter更灵活一些,而且可以直接结合spring的其他方法来使用,扩展性也强

三、AOP

  • AOP即面向切面编程,简单的来说就是在普通的顺序执行的代码中,创造一个切点,然后在对切点进行前置通知,后置通知代码的描述,
  • @Aspect 声明切面,可以在类、接口、枚举中使用
  • @Pointcut 声明切点,用于关联切点,可使用表达式
  • @Before 前置通知,在切点执行之前运行
  • @After 后置通知,在切点执行之后运行
  • @AfterReturning 增强后置通知,可以获取切点的返回值
  • @AfterThrowing 异常通知,当接口发生错误时,进入异常通知,但是如果异常被捕获,则不会进入异常通知
  • @Around 环绕通知,会在切点执行前后分别执行,环绕通知的优先级大于前置通知以及后置通知

四、实现步骤

  • 第一步创建切面
@Aspect
@Component
public class UrlAspect {
	// 创建一个线程空间,来存放接口执行的开始毫秒数
    private ThreadLocal<Long> threadLocal = new ThreadLocal<>();
}
  • 第二步创建切点以及需要扫描的控制器
    @Pointcut("execution(* com.xc..controller.MonitorController.*(..))")
    public void logCut() {
    }
  • 第三步创建前置通知
    @Before("logCut()")
    public void beforeLog(JoinPoint joinPoint) throws IOException {// 保存接口开始执行的时间
        long startTime = System.currentTimeMillis();
        threadLocal.set(startTime);
    }
  • 第四步创建增强后置通知
    @AfterReturning(value = "logCut()", returning = "result")
    public void returningLog(JoinPoint joinPoint, Object result) {
    	// 获取HttpServletRequest对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 获取HttpServletResponse对象
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
		
		// 通过线程空间存储的接口开始时间计算接口耗时
        Long startTime = threadLocal.get();
        long endTime = System.currentTimeMillis();

		// 获取接口参数
        Object[] args = joinPoint.getArgs();

		// 将接口的请求响应信息存储到数据库中
        LogBean logBean = new LogBean();
        logBean.setRequestUrl(request.getRequestURL().toString())
                .setRequestType(request.getMethod())
                .setRequestParmeter(Arrays.stream(args).map(Object::toString).collect(Collectors.joining(",")))
                .setResponseStatus(String.valueOf(response.getStatus()))
                .setResponseResult(result.toString())
                .setResponseTime(String.valueOf(endTime - startTime));
        logService.addLog(logBean);
    }
  • 第五步创建异常通知
    @AfterThrowing(value = "logCut()", throwing = "exception")
    public void throwingLog(JoinPoint joinPoint, Throwable exception) {
    	// 获取HttpServletRequest对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 获取HttpServletResponse对象
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();

		// 通过线程空间存储的接口开始时间计算接口耗时
        Long startTime = threadLocal.get();
        long endTime = System.currentTimeMillis();

		// 获取接口参数
        Object[] args = joinPoint.getArgs();

		// 将接口的请求响应信息存储到数据库中
        LogBean logBean = new LogBean();
        logBean.setRequestUrl(request.getRequestURL().toString())
                .setRequestType(request.getMethod())
                .setRequestParmeter(Arrays.stream(args).map(Object::toString).collect(Collectors.joining(",")))
                .setResponseStatus(String.valueOf(response.getStatus()))
                .setResponseResult(exception.getMessage())
                .setResponseTime(String.valueOf(endTime - startTime));
        logService.addLog(logBean);
    }
  • 第六步创建控制器查看监听器的调用结果
@RestController
@RequestMapping("/monitor")
public class MonitorController {

    @GetMapping("/getRequset/{id}")
    public String getRequset(String name, @PathVariable("id") String id) {
        return "这里是GET请求";
    }

    @PutMapping("/putRequset")
    public String putRequset() {
        return "这里是PUT请求";
    }

    @PostMapping("/postRequset")
    public String postRequset() {
        return "这里是POST请求";
    }

    @DeleteMapping("/deleteRequset")
    public String deleteRequset() {
        return "这里是DELETE请求";
    }

}

在这里插入图片描述
在这里插入图片描述

五、总结

不知不觉已经毕业两年了,工作了这么久,才开始用这些面试经常用到的技术,略微有些惭愧,但是好过不学,现在还是需要保持经常学习的态度,我的技术还有待提高,我的目标是能开发出高可用的接口,拒绝死代码
需要该完整代码的小伙伴可以访问https://github.com/bugMakker/myWorkSpace/tree/xc

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Spring AOP实现接口访问量统计,可以按照以下步骤进行: 1. 定义一个注解@AccessCount,用于标记需要统计访问量的方法。 ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AccessCount { } ``` 2. 定义一个切面类AccessCountAspect,用于统计被@AccessCount标记的方法的访问量。这个类需要实现org.aspectj.lang.annotation.Aspect接口,并使用@Aspect注解标记。 ```java @Aspect @Component public class AccessCountAspect { private Map<String, Integer> accessCounts = new ConcurrentHashMap<>(); @Pointcut("@annotation(com.example.demo.annotation.AccessCount)") public void accessCountPointcut() {} @Around("accessCountPointcut()") public Object accessCountAround(ProceedingJoinPoint joinPoint) throws Throwable { String methodName = joinPoint.getSignature().toShortString(); int count = accessCounts.getOrDefault(methodName, 0); accessCounts.put(methodName, count + 1); return joinPoint.proceed(); } public Map<String, Integer> getAccessCounts() { return accessCounts; } } ``` 3. 在Spring配置文件中定义切面和切点。 ```xml <aop:aspectj-autoproxy/> <bean id="accessCountAspect" class="com.example.demo.aspect.AccessCountAspect"/> <aop:config> <aop:aspect ref="accessCountAspect"> <aop:pointcut id="accessCountPointcut" expression="execution(* com.example.demo.service..*(..))"/> <aop:around method="accessCountAround" pointcut-ref="accessCountPointcut"/> </aop:aspect> </aop:config> ``` 4. 在需要统计访问量的方法上添加@AccessCount注解。 ```java @Service public class UserServiceImpl implements UserService { @AccessCount @Override public User getUserById(Long id) { // ... } } ``` 5. 在需要获取访问量的地方,注入AccessCountAspect并调用getAccessCounts方法。 ```java @RestController @RequestMapping("/access-count") public class AccessCountController { @Autowired private AccessCountAspect accessCountAspect; @GetMapping("") public Map<String, Integer> getAccessCounts() { return accessCountAspect.getAccessCounts(); } } ``` 这样就可以使用Spring AOP实现接口访问量统计了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值