上文我们学习了AOP面向切面编程的基础和相关知识,了解到它可以在不修改源代码的基础上为程序打造监控日志,本文我们开展实践,利用AOP切面技术为主流RESTFul-API接口打造一个统一的访问日志,实现登录IP、访问方法、传入参数等信息的记录。
项目架构:作用于标准RESTFul-API接口,暂不设置登录和认证机制。
思路:在不修改任何接口源代码的基础上,新增一个Before切面,切入点包含API接口下面的所有类、接口、方法,记录传入参数。
(1)接口IP地址:由ServletRequestAttributes(getRequestURL())提供。ServletRequestAttributes是SpringMVC封装的ThreadLocal,保存了每次Http请求的HttpServletRequest对象。
(2)访问接口对方IP地址:由ServletRequestAttributes(getRemoteAddr())提供。
(3)接口类路径名称:由切面连接点JoinPoint(getSignature().getDeclaringTypeName())提供。
(4)接口方法名称:由切面连接点JoinPoint(getSignature().getName())提供。
(5)传入参数:由切面连接点JoinPoint(getArgs())提供。
这里原来有一个实体类Book和一个RESTFul-API接口BookRepository用来实现查询get、修改put、新增post、删除delete等基本操作,对接口我们不做任何源代码修改,在顶层package下面创建一个Aoplog类,用来实现AOP切面和访问日志输出。
package com.example.demohelloworld.restful; 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.slf4j.Logger; import org.slf4j.LoggerFactory; 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; @Component @Aspect public class Aoplog { //定义日志输出 Logger logger= LoggerFactory.getLogger(this.getClass()); //定义切入点 @Pointcut("execution(* com.example.demohelloworld.restful.APIRepository.*.*(..))") public void getlog(){ } //构建一个Before前置通知,在方法执行之前执行,可获取传入参数 @Before(value = "getlog()") public void before(JoinPoint joinPoint){ //通过ServletRequestAttributes获取Http访问接口请求信息 ServletRequestAttributes attributes= (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); HttpServletRequest request=attributes.getRequest(); //接口IP地址 logger.info("url={}",request.getRequestURL()); //访问接口对方IP地址 logger.info("ip={}",request.getRemoteAddr()); //接口类路径名称 logger.info("class={}",joinPoint.getSignature().getDeclaringTypeName()); //接口方法名称 logger.info("method={}",joinPoint.getSignature().getName()); //传入参数,格式为Object[],使用Arrays.deepToString进行转化 logger.info("args={}", Arrays.deepToString(joinPoint.getArgs())); } }
我们启动项目,利用POSTMAN访问API接口:
findById查询单条数据,访问日志输出如下:
findAll批量查询,访问日志输出如下,传入参数我们加入了分页,每页条数和按ID倒叙排列:
save新增Book数据,访问日志输出如下:
AOP切面编程能够在不修改源码的情况下,非常方便地实现系统监控、日志输出等功能,并且是独立的模块,利于维护。
当然AOP还有非常多的应用场景,本文仅做了访问日志基础应用示例,后续还需要不断探索实践。