一、理論基礎
1.1 AOP是什么
- AOP(Aspect Oriented Programming)--面向切面編程
- 可以通過預編譯方式和運行期動態(tài)代理實現(xiàn)在不修改源代碼的情況下給程序動態(tài)統(tǒng)一添加功能的一種技術
以上介紹來自百度百科-AOP
1.2 AOP能做什么
- 統(tǒng)計接口訪問次數(shù)
- 增強功能:在不改動代碼的情況下,為接口增加一些額外的功能
二、實戰(zhàn)代碼
2.1 依賴引入
<!-- 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>
2.2 AOP示例
/**
* API訪問歷史統(tǒng)計
* @author yangjunqiang
*/
@Component
@Aspect
public class ApiVisitHistory {
private Logger log = LoggerFactory.getLogger(ApiVisitHistory.class);
ThreadLocal<Long> startTime = new ThreadLocal<>();
/**
* 定義切面
* - 此處代表com.smile.demo.controller包下的所有接口都會被統(tǒng)計
*/
@Pointcut("execution(* com.smile.demo.controller..*.*(..))")
public void pointCut(){
}
/**
* 在接口原有的方法執(zhí)行前,將會首先執(zhí)行此處的代碼
*/
@Before("pointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
startTime.set(System.currentTimeMillis());
//獲取傳入目標方法的參數(shù)
Object[] args = joinPoint.getArgs();
log.info("類名:{}", joinPoint.getSignature().getDeclaringType().getSimpleName());
log.info("方法名:{}", joinPoint.getSignature().getName() );
// 計數(shù)
AtomicCounter.getInstance().increase();
}
/**
* 只有正常返回才會執(zhí)行此方法
* 如果程序執(zhí)行失敗,則不執(zhí)行此方法
*/
@AfterReturning(returning = "returnVal", pointcut = "pointCut()")
public void doAfterReturning(JoinPoint joinPoint, Object returnVal) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
log.info("所有接口的總點擊:{}", AtomicCounter.getInstance().getValue());
}
/**
* 當接口報錯時執(zhí)行此方法
*/
@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!";
}
@GetMapping("hello2")
public String hello2() {
int i = 1 / 0;
return "測試報錯的AOP方法";
}
}
2.4 源碼地址
https://github.com/lysmile/spring-boot-demo/tree/master/springboot-aop-demo