Spring Aop切面参数JoinPoint详解
Spring AOP简单实现全局日志监控请求
前言
Spring AOP意为:面向切面编程。同时AOP也是基于动态代理和反射进行实现,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。在学习AOP之前有兴趣的同学可以先了解一下IOC,链接:Spring IOC详解
AOP日志功能实战
在此demo只介绍了以自定义注解标记的方法作为切点。首先我们先自定义一个注解,里面包含了日志的信息。
RequestTime.java
import java.lang.annotation.*;
/** 请求时间注解 @Author liaopj 2022/4/12 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestTime {
/**
* 日志模块
*/
public String title() default "";
}
接下来编写我们的切面类,这里需要注意我们可以先看一下切面表达式,我们也可以自定义切面表达式来实现我们想要实现切面的地方,链接:切面表达式
RequestTimeAspect.java
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/** 请求日志aop @Author liaopj 2022/4/12 */
@Aspect
@Component
@Slf4j
public class RequestTimeAspect {
/**
* 环绕请求 只对刚刚我们自定义注解标记的方法生效,当然也可以指定某一个包或者某多个包下的所有方法生效
* @Around注解可以用来在调用一个具体方法前和调用后来完成一些具体的任务
* 更多注解可以看上方的Spring Aop切面参数JoinPoint详解链接
* @param joinPoint 切点
*/
@Around(value = "@annotation(requestTime)")
public Object RequestTime(ProceedingJoinPoint joinPoint, RequestTime requestTime)
throws Throwable {
// 请求前的时间戳
long startTime = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
// 请求后的时间戳
long endTime = System.currentTimeMillis();
// 请求详细信息
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String method = request.getMethod();
String requestURI = request.getRequestURI();
long Time = endTime - startTime;
log.info(
"请求信息method:{},requestURI:{},time:{}ms,日志模块:{}",
method,
requestURI,
Time,
requestTime.title());
return proceed;
}
这时候我们的切面就定义好了,下面就来使用我们的AOP
比如这时候我有一个往redis里添加缓存的接口,我需要监控这个接口的请求时间或者请求路径等一些信息。代码如下:
RedisDemoController.java
import com.liao.aspectj.RequestTime;
import com.liao.redis.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/** @Author liaopj 2022/4/11 */
@RestController
@RequestMapping("/redis")
@Slf4j
public class RedisDemoController {
@Autowired private RedisUtil redisUtil;
@GetMapping("/Test")
@RequestTime(title ="redis模块")
public void redisTest() {
Map<String, String> map = new HashMap<String, String>();
map.put("test", "test");
redisUtil.setCacheMap("REDIS_DEMO:redisTest", map);
redisUtil.expire("REDIS_DEMO:redisTest", 10);
log.info("redis中成功缓存,过期时间为time:{}s,key:{},value:{}", "10", "REDIS_DEMO:redisTest", map);
}
@GetMapping("/Test02")
public void redisTest02() {
System.out.println("当我们调用此接口时,他没有被@RequestTime标记,所以我们AOP不会生效");
}
}
这时候我们自定义的AOP就生效了
这里一个是我们接口打印的日志,一个是AOP打印的请求信息日志。
此时,一个Spring AOP的一个小demo就完成了。具体AOP的应用还有很多知识。