Spring AOP是面向切面編程,切面有幾個重要概念:
切面:連接點、切點、通知所在的【類】就是切面 切點:連接點的集合 連接點:可以理解爲spring的方法 通知:切入切點的時機before、after等 業務
在spring-boot中的簡單應用
1:在pom中加入aop的依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2:編輯切面:
這是一個關於日誌的切面(類),
通過@Pointcut("execution(* com.teligen.dazt.learn.spring.aop.service..*.*(..))")設置切點
通過 @Before("logPointCut()") @After("logPointCut()") 設置通知業務。
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/**
* 一個日誌的切面
*/
@Component
@Aspect
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
/**
* 日誌切點
*/
@Pointcut("execution(* com.teligen.dazt.learn.spring.aop.service..*.*(..))")
public void logPointCut(){
}
/**
* 日誌開始
*/
@Before("logPointCut()")
public void logBefore(){
// logger.info("before ...");
logger.info("before");
}
/**
* 日誌結束
*/
@After("logPointCut()")
public void logAfter(){
// logger.info("after ...");
logger.info("after");
}
/**
* 日誌環繞
*/
@Around("logPointCut()")
public void logAround(ProceedingJoinPoint joinPoint){
try {
logger.info("around start");
Signature signature = joinPoint.getSignature();
//方法名
String methodName = signature.getName();
//類型
String serviceName = signature.getDeclaringTypeName();
// 參數名數組
String[] parameterNames = ((MethodSignature) signature).getParameterNames();
// 構造參數組集合
List<Object> argList = new ArrayList<>();
for (Object arg : joinPoint.getArgs()) {
// request/response無法使用toJSON
if (arg instanceof HttpServletRequest) {
argList.add("request");
} else if (arg instanceof HttpServletResponse) {
argList.add("response");
} else {
argList.add(JSON.toJSON(arg));
}
}
try {
logger.info("{} -> 方法({}) -> 參數:{} - {}", serviceName, methodName, JSON.toJSON(parameterNames), JSON.toJSON(argList));
} catch (Exception e) {
logger.error("參數獲取失敗: {}", e.getMessage());
}
long startTime = System.currentTimeMillis();
Object data = joinPoint.proceed();
logger.info("joinPoint.proceed 執行結果: "+data);
long endTime = System.currentTimeMillis();
logger.info("around end 時間:"+(endTime - startTime));
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
3:編寫相關的測試方法
package com.teligen.dazt.learn.spring.aop.service.impl;
import com.teligen.dazt.learn.spring.aop.service.MyService;
import org.springframework.stereotype.Service;
@Service
public class MyServiceImpl implements MyService {
@Override
public String doAnalyse() throws InterruptedException {
System.out.println("開始進行分析...");
Thread.sleep(1000);
System.out.println("結束分析...");
return "執行成功";
}
}
運行結果:
2020-03-03 15:58:13.046 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : around start
2020-03-03 15:58:13.354 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : com.teligen.dazt.learn.spring.aop.service.impl.MyServiceImpl -> 方法(doAnalyse) -> 參數:[] - []
2020-03-03 15:58:13.397 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : before
開始進行分析...
結束分析...
2020-03-03 15:58:14.406 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : joinPoint.proceed 執行結果: 執行成功
2020-03-03 15:58:14.406 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : around end 時間:1009
2020-03-03 15:58:14.407 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : after