java AOP aspect programming practice

This example is an annotation based aspect programming practice. This aspect function is mainly used to count the execution time of the annotated method

1. First configure maven dependency:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- aop -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
		</dependency>

2. Define an annotation

package com.example.interceptor.aop;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TimeLog {
    String value() default "";
}

3. Define an annotation based section and write corresponding pre and post enhancement methods

package com.example.interceptor.aop;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Monitoring log cutter
 * @author weichangzhong
 * @Aspect The function is to identify the current class as a tangent for the container to read
 */
@Slf4j
@Aspect
@Component
@Order(1)
public class LogAspect {

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

    /**
     *  The set of pointcut JoinPoint is the set of positions that need to be injected into Advice in the program. It indicates the conditions under which Advice can be triggered. It is mainly embodied in writing pointcut expressions in the program
     *  It is defined by the following methods or combined by & &, |,!, and, for example:
     *  execution: Connection point for matching method execution
     *  @annotation: Method used to match the current execution method with the specified annotation
     */
    @Pointcut("@annotation(com.example.interceptor.aop.TimeLog)")
    public void logPointCut() {

    }

    /**
     *  Identify a pre enhancement method, equivalent to the function of BeforeAdvice. Execute before the pointcut method
     */
    @Before("logPointCut()")
    public void before() {
        log.info("--------------before----------logPointCut");
        startTime.set(System.currentTimeMillis());
    }

    /**
     * Post enhancement, similar to AfterReturningAdvice, is performed when the method returns and exits normally
     * returning The value of corresponds to the return value of the business method, and its name should be the same as the parameter name of the afterReturning method
     */
    @AfterReturning(pointcut = "logPointCut()", returning = "response")
    public void afterReturning(JoinPoint joinPoint, Object response) {
        Long cost = System.currentTimeMillis() - startTime.get();
        log.info("--------------afterReturn--------logPointCut, time: {}", cost);

        //Get method type
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = joinPoint.getTarget().getClass().getName();
        TimeLog annotation = method.getAnnotation(TimeLog.class);
        if(annotation == null) {
            log.info("ClassName: {}, methodName: {}", className, method.getName());
        }else {
            log.info("The value of annotation is: {}, className: {}, methodName: {}", annotation.value(), className, method.getName());
        }

        //Get request parameters
        Object[] args = joinPoint.getArgs();
        if (ArrayUtils.isNotEmpty(args)) {
            //The parameters of httpServletRequest, httpServletResponse and multipartFile are asynchronously assembled and cannot be serialized, so they need to be filtered out
            List<Object> filterArg = Arrays.stream(args).filter(
                    arg -> !(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse) && !(arg instanceof MultipartFile)
            ).collect(Collectors.toList());
            log.info("The parameter is: {}", filterArg.toString());
        }else{
            log.info("The parameter is: {}", args);
        }
    }

    /**
     * Exception throwing enhancement, equivalent to throw exception execution of ThrowsAdvice. Pointcut method
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(pointcut = "logPointCut()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        Long cost = System.currentTimeMillis() - startTime.get();
        if (log.isDebugEnabled()) {
            log.debug("----------afterThrow--------logPointCut, time: {}", cost);
        }
    }
}

3. Finally, define a intercepted controller method

package com.example.interceptor.controller;

import com.example.interceptor.aop.TimeLog;
import com.example.interceptor.service.TestService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author weichangzhong
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @Resource
    private TestService testService;

    @GetMapping
    @TimeLog("test-1")
    public String getTest(@RequestParam String name, String email) {
        return testService.getTestString();
    }
}

service layer:

package com.example.interceptor.service;

import com.example.interceptor.aop.TimeLog;
import org.springframework.stereotype.Service;

/**
 * @author weichangzhong
 */
@Service
public class TestService {

    @TimeLog
    public String getTestString() {
        return "test response";
    }
}

After starting the service, call the interface: localhost: 8080 / test? Name = me & email = emailtest

 

184 original articles published, 87 praised, 570000 visitors+
His message board follow

Tags: Java Spring Apache Programming

Posted on Sat, 18 Jan 2020 09:12:04 -0500 by anatak