AOP实现日志

作者: Ian | 2019-02-23 | 阅读

参考:iteye_16572 – https://blog.csdn.net/iteye_16572/article/details/82677981 参考:山高我为峰 – https://www.cnblogs.com/liaojie970/p/7883687.html

实现AOP的切面主要有以下几个要素:

  1. 使用@Aspect注解将一个java类定义为切面类
  2. 使用@Pointcut定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等。
    1. 修饰符匹配(modifier-pattern?)
    2. 返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等
    3. 类路径匹配(declaring-type-pattern?)
    4. 方法名匹配(name-pattern)可以指定方法名 或者 代表所有, set 代表以set开头的所有方法
    5. 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(..)表示零个或多个任意参数
    6. 异常类型匹配(throws-pattern?)
    7. 其中后面跟着“?”的是可选项
      // 栗子:
      1execution(* *(..))  
      //表示匹配所有方法  
      2execution(public * com. savage.service.UserService.*(..))  
      //表示匹配com.savage.server.UserService中所有的公有方法  
      3execution(* com.savage.server..*.*(..))  
      //表示匹配com.savage.server包及其子包下的所有方法
      
  3. 根据需要在切入点不同位置的切入内容
  4. 使用@Before在切入点开始处切入内容
  5. 使用@After在切入点结尾处切入内容
  6. 使用@AfterReturning在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
  7. 使用@Around在切入点前后切入内容,并自己控制何时执行切入点自身的内容
  8. 使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑

栗子:

import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
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;


// ① 在类上使用 @Component 注解 把切面类加入到IOC容器中 
// ② 在类上使用 @Aspect 注解 使之成为切面类

@Aspect
@Component
public class ControllerLogAspect {

    private Logger logger = LoggerFactory.getLogger(ControllerLogAspect.class);

    private ThreadLocal<Long> startTime = new ThreadLocal<Long>();

    @Pointcut("execution(public * .*.controller..*.*(..))")
    public void controllerLog() {}

    @Before("controllerLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {

        ServletRequestAttributes attributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 请求内容
        logger.info("请求地址 : " + request.getRequestURL().toString() 
        		+ ",参数 : " + Arrays.toString(joinPoint.getArgs())
        		+ ",请求方法 : " + request.getMethod() 
        		+ ",IP: " + request.getRemoteAddr() 
        		+ ",CLASS_METHOD: " + joinPoint.getSignature().getDeclaringTypeName() + "."
                + joinPoint.getSignature().getName());

    }

    @AfterReturning(returning = "ret", pointcut = "controllerLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 返回内容
        logger.info("返回值 : " + ret);
    }

    @Around("controllerLog()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        startTime.set(System.currentTimeMillis());
        Object ob = pjp.proceed();// ob 为方法的返回值
        logger.info("耗时 : " + (System.currentTimeMillis() - startTime.get()));
        return ob;
    }
}
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
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;


// ① 在类上使用 @Component 注解 把切面类加入到IOC容器中 
// ② 在类上使用 @Aspect 注解 使之成为切面类
@Aspect
@Component
public class ServiceLogAspect {

    private Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);

    private ThreadLocal<Long> startTime = new ThreadLocal<Long>();

    @Pointcut("execution(public * .*.service..*.*(..))")
    public void serviceLog() {}

    @Before("serviceLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 请求内容
        logger.info("CLASS_METHOD: " + joinPoint.getSignature().getDeclaringTypeName() + "."
                + joinPoint.getSignature().getName() + ",参数 : "
                + Arrays.toString(joinPoint.getArgs()));
    }

    @AfterReturning(returning = "ret", pointcut = "serviceLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 返回内容
        logger.info("返回值 : " + ret);
    }

    @Around("serviceLog()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        startTime.set(System.currentTimeMillis());
        Object ob = pjp.proceed();// ob 为方法的返回值
        logger.info("耗时 : " + (System.currentTimeMillis() - startTime.get()));
        return ob;
    }
}

文章中若有不足之处,还望指出。坚持是一种精神,分享是一种快乐!



  相关文章:


留言区:

TOP