SpringBoot AOP實現介面次數訪問統計
阿新 • • 發佈:2022-12-02
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();
}
}