Advice:通知,某个连接点所采用的处理逻辑,也就是向连接点注入的代码, AOP在特定的切入点上执行的增强处理。

@Before:标识前置增强方法,相当于BeforeAdvice;
@Around:环绕增强,相当于MethodInterceptor;
@After:final增强,抛出异常和正常退出后都会执行;
@AfterReturning:后置增强,正常退出时执行,相当于AfterReturningAdvice;
@AfterThrowing:后置增强,抛出异常时执行,相当于ThrowsAdvice。
JointPoint:连接点,程序运行中的某个阶段点,比如方法的调用、异常的抛出等。

Object[] getArgs:返回目标方法的参数;
Signature getSignature:返回目标方法的签名;
Object getTarget:返回被织入增强处理的目标对象;
Object getThis:返回AOP框架为目标对象生成的代理对象

<!-- AOP -->
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjrt</artifactId>
	<version>1.9.4</version>
</dependency>
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.9.4</version>
</dependency>
<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>3.2.12</version>
</dependency>
import com.example.demo.module.annotation.SystemLog;
import com.example.demo.module.utils.AtomicCounter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * <p> @Title ApiVisitHistory
 * <p> @Description API访问历史统计
 *
 * @author ACGkaka
 * @date 2021/3/31 17:29
 */
@Component
@Aspect
public class ApiLogAopAction {

    private static final Logger LOGGER = LoggerFactory.getLogger(ApiLogAopAction.class);

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

    @Autowired
    HttpServletRequest request;

    /**
     * 定义切面
     * - 此处代表com.example.demo.module.controller包下的所有接口都会被统计
     */
    @Pointcut("@annotation(com.example.demo.module.annotation.SystemLog)")
    // @Pointcut("execution(* cn.agile.platform.core.web.controller..*.*(..))")
    public void log() {
    }

    /**
     * 在接口原有的方法执行前,将会首先执行此处的代码
     */
    @Before("log()")
    public void doBefore(JoinPoint joinPoint) {
        startTime.set(System.currentTimeMillis());
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        SystemLog annotation = signature.getMethod().getAnnotation(SystemLog.class);
        AtomicCounter.init(annotation.module(), request.getRequestURI());
        // 计数
        AtomicCounter.getInstance().increaseVisit(request.getRequestURI());
    }

    /**
     * 只有正常返回才会执行此方法
     * 如果程序执行失败,则不执行此方法
     */
    @AfterReturning(returning = "returnVal", pointcut = "log()")
    public void doAfterReturning(JoinPoint joinPoint, Object returnVal) {
        LOGGER.info("URI:[{}], 耗费时间:[{}] ms, 访问次数:{}", request.getServletPath(), System.currentTimeMillis() - startTime.get(), AtomicCounter.getInstance().increaseSuccess(request.getRequestURI()));
    }

    /**
     * 当接口报错时执行此方法
     */
    @AfterThrowing(pointcut = "log()")
    public void doAfterThrowing(JoinPoint joinPoint) {
        LOGGER.info("接口访问失败,URI:[{}], 耗费时间:[{}] ms", request.getServletPath(), AtomicCounter.getInstance().increaseFail(request.getRequestURI()));
    }

    /**
     * 在接口原有的方法执行后,都会执行此处的代码(final)
     */
    @After("log()")
    public void doAfter(JoinPoint joinPoint) {
        LOGGER.info("End.{}", AtomicCounter.getInstance().getValue(request.getRequestURI()));
    }
}
import java.lang.annotation.*;

/**
 * <p> @Title SystemLog
 * <p> @Description 接口日志注解
 *
 * @author ACGkaka
 * @date 2021/4/1 11:36
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLog {
    String module()  default "";//模块
    String method()  default "";//方法
    String operateType() default "OTHER" ;//事件类型:LOGIN;LOGINOUT;ADD;DELETE;UPDATE;SELETE;UPLOAD;DOWNLOAD;OTHER
    String logType() default "0";//日志类型:0:系统日志;1:业务日志
}
import com.example.demo.module.annotation.SystemLog;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p> @Title DemoController
 * <p> @Description 待统计接口
 *
 * @author ACGkaka
 * @date 2021/3/31 17:24
 */
@RestController
public class DemoController {

    @GetMapping("/index")
    @SystemLog(module = "首页", method = "hello", operateType = "SELECT", logType = "1")
    public String index() {
        return "<h1>Hello World.</h1>";
    }

    @GetMapping("login")
    @SystemLog(module = "首页", method = "login", operateType = "LOGIN", logType = "1")
    public String login() {
        int i = 1 / (Math.random() > 0.5 ? 0 : 1);
        return "测试报错的AOP方法";
    }
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐