1. 程式人生 > 其它 >SpringBoot AOP實現介面次數訪問統計

SpringBoot AOP實現介面次數訪問統計

1 理論基礎

1.1 AOP是什麼

  • 面向切面程式設計(AOP,Aspect Oriented Programming)

  • 可以通過預編譯方式和執行時動態代理,實現在不修改原始碼的情況下,給程式動態增強功能的的一種技術

1.2 AOP能做什麼

  • 統計介面訪問次數
  • 資料庫事務處理
  • 增強功能:在不改動原始碼的基礎上,為介面增加一些額外的功能

2 Demo程式碼

2.1 引入依賴

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId
>
spring-boot-starter-web</artifactId> </dependency> <!-- 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
>
<!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.70</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>

2.2 API訪問歷史統計

/**
 * API訪問歷史統計
 */
@Component
@Aspect
public class ApiVisitHistory {

    private Logger log = LoggerFactory.getLogger(ApiVisitHistory.class);

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

    /**
     * 定義切面
     * - 此處代表com.smile.demo.controller包下的所有介面都會被統計
     */
    @Pointcut("execution(* com.smile.demo.controller..*.*(..))")
    public void pointCut(){

    }

    /**
     * 在介面原有的方法執行前,將會首先執行此處的程式碼
     */
    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint) {
        startTime.set(System.currentTimeMillis());
        //獲取傳入目標方法的引數
        Object[] args = joinPoint.getArgs();
        log.info("類名:{}", joinPoint.getSignature().getDeclaringType().getSimpleName());
        log.info("方法名:{}", joinPoint.getSignature().getName() );
        // 計數
        AtomicCounter.getInstance().increase();
    }

    /**
     * 只有正常返回才會執行此方法
     * 如果程式執行失敗,則不執行此方法
     */
    @AfterReturning(returning = "returnVal", pointcut = "pointCut()")
    public void doAfterReturning(JoinPoint joinPoint, Object returnVal) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        log.info("URI:[{}], 耗費時間:[{}] ms, 訪問次數:{}", request.getRequestURI(), System.currentTimeMillis() - startTime.get(), AtomicCounter.getInstance().getValue());
    }

    /**
     * 當介面報錯時執行此方法
     */
    @AfterThrowing(pointcut = "pointCut()")
    public void doAfterThrowing(JoinPoint joinPoint) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        log.info("介面訪問失敗,URI:[{}], 耗費時間:[{}] ms", request.getRequestURI(), System.currentTimeMillis() - startTime.get());
    }
}

2.3 定義測試介面

@RestController
@RequestMapping("/demo/aop")
public class HelloController {

    @GetMapping("hello")
    public String hello() {
        return "hello World!";
    }
}
@RestController
@RequestMapping("/demo/aop")
public class ErrorController {
    @GetMapping("error")
    public String error() {
        int i = 1 / 0;
        return "測試報錯的AOP方法";
    }
}

2.4 單例計數器

/**
 * 計數器,統計當前執行的任務數
 *
 */
public class AtomicCounter {

	private static final AtomicCounter atomicCounter = new AtomicCounter();
	
	/**
	 * 單例,不允許外界主動例項化
	 */
	private AtomicCounter() { 
		
	}
	
	public static AtomicCounter getInstance() {
		return atomicCounter;
	}
	
	private static AtomicInteger counter = new AtomicInteger();
	
	public int getValue() {
		return counter.get();
	}
	
	public int increase() {
		return counter.incrementAndGet();
	}
	
	public int decrease() {
		return counter.decrementAndGet();
	}
	
}