AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是Spring框架中的一個重要內容,它通過對既有程序定義一個切入點,然後在其前後切入不同的執行內容,比如常見的有:打開數據庫連接/關閉數據庫連接、打開事務/關閉事務、記錄日誌等。基於AOP不會破壞原來程序邏輯,因此它可以很好的對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
實現Web層的日誌切面
實現AOP的切面主要有以下幾個要素:
- 使用
@Aspect
註解將一個java類定義爲切面類 - 使用
@Pointcut
定義一個切入點,可以是一個規則表達式,比如下例中某個package下的所有函數,也可以是一個註解等。 - 根據需要在切入點不同位置的切入內容
- 使用
@Before
在切入點開始處切入內容 - 使用
@After
在切入點結尾處切入內容 - 使用
@AfterReturning
在切入點return內容之後切入內容(可以用來對處理返回值做一些加工處理) - 使用
@Around
在切入點前後切入內容,並自己控制何時執行切入點自身的內容 - 使用
@AfterThrowing
用來處理當切入內容部分拋出異常之後的處理邏
- 使用
示例
@Aspect
@Component
public class WebLogAspect {
private static final String POINT_CUT = "execution(public * com.xx.xx.xx..*.*(..)) && !execution(public * com.xx.xx.xx.CommonController.*(..))";
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private ThreadLocal<Long> startTime = new ThreadLocal<>();
@Pointcut(POINT_CUT)
public void webLog() {
}
@Before("webLog()")
public void before(JoinPoint joinPoint) {
startTime.set(System.currentTimeMillis());
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
StringBuilder logInfo = new StringBuilder();
logInfo.append(request.getRemoteAddr()).append(" ").append(request.getRequestURL().toString()).append("/");
logger.info("■■■BEFORE■■■:IP={},URL={}?{}", request.getRemoteAddr(),
request.getRequestURL().toString(), getParams(request));
}
private String getParams(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
Set<Entry<String, String[]>> entrySet = parameterMap.entrySet();
StringBuilder sb = new StringBuilder();
for (Entry<String, String[]> entry : entrySet) {
sb.append(entry.getKey()).append("=").append(entry.getValue()[0]).append("&");
}
return sb.toString()+"&deviceType="+request.getHeader("deviceType");
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) {
Long time = System.currentTimeMillis() - startTime.get();
logger.info("■■■AFTER■■■:{},RESPONSE : {}ms", time, ret);
}
@AfterThrowing(value = POINT_CUT, throwing = "e")
public void afterThrowing(Throwable e) {
logger.error("afterThrowing: " + e.getMessage(), e);
}
}