spring boot使用aop拦截Controller和Service以方便调试
调试的时候,经常需要看每个函数的输入输出,以前每次都是System.out.println
输出,调试完后还要删掉,要是每次都能自己输出函数的输入输出就好了。
在网上找了一通,结合《Spring 实战》写了一个自己用的切面
- BaseAspect
public abstract class BaseAspect {
protected Object process(ProceedingJoinPoint pjp, StringBuilder sb) throws Throwable {
//获取连接点目标类名
String targetName = pjp.getTarget().getClass().getName();
//获取连接点签名的方法名
String methodName = pjp.getSignature().getName();
//获取连接点参数
Object[] args = pjp.getArgs();
//根据连接点类的名字获取指定类
Class targetClass = Class.forName(targetName);
//获取类里面的方法
Method[] methods = targetClass.getMethods();
Object object = pjp.proceed();
sb.append(targetClass.getCanonicalName())
.append(methodName)
.append(JSON.toJSONString(args))
.append(object);
return object;
}
}
- ControllerDebugAspect
/**
* Controller调试用切面,可以快速了解输入输出是
*/
@Aspect
@Component
@Slf4j
public class ControllerDebugAspect extends BaseAspect{
@Pointcut("execution(* api.*.controller.*.*(..)) || execution(* api.controller.*.*(..))")
public void Pointcut() {
}
@Around("Pointcut()")
public Object Around(ProceedingJoinPoint pjp) throws Throwable {
StringBuilder sb = new StringBuilder();
Object object = process(pjp, sb);
logger.debug(sb.toString());
return object;
}
}
- ServiceDebugAspect
@Aspect
@Component
@Slf4j
public class ServiceDebugAspect extends BaseAspect{
// @Pointcut("@annotation(org.springframework.web.bind.annotation.RestController) || @annotation(org.springframework.stereotype.Service)")
@Pointcut("execution(* api.*.service.impl.*.*(..)) || execution(* api.service.impl.*.*(..))")
public void Pointcut() {
}
@Around("Pointcut()")
public Object Around(ProceedingJoinPoint pjp) throws Throwable {
StringBuilder sb = new StringBuilder();
Object object = process(pjp, sb);
logger.debug(sb.toString());
return object;
}
}
后面两个其实是一样的。
在调试的时候,IDEA有一个按钮
每次写完Pointcut表达式,按一下可以知道有哪些方法会生效
除了代码,还有两个地方
一个是application.properties文件
#aop
spring.aop.proxy-target-class=true
spring.aop.auto=true
一个是在@SpringBootApplication
所在的类上写注解
@EnableAspectJAutoProxy(exposeProxy=true)
后来测了一下,去掉注解也是可以的
看了一**解源码
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
使用注解和写application.properties文件应该是等价的