spring aop 日志攔截器的實現(原創)
利用 spring aop 的 around 來實現日志攔截器,此攔截器負責打印拋出到頂層的異常日志。
具體實現
引入相關切面依賴
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.9</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.9</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2</version> </dependency>
實現日志攔截器
攔截異常打印日志,注意用線程本地變量startLocal,來做一個是否為第一個(入口)本地方法的標志。這樣做的目的是為了避免重復在每個方法里catch異常, 拋出異常操作的時候打印異常。注意catch的是 java.lang.Throwable級別的異常。包括所有的errors 和 exceptions。
public class LogInterceptor { private final Logger logger = LoggerFactory.getLogger(LogInterceptor.class); /** * 首次進入標志 */ private static final ThreadLocal<Boolean> startLocal = new ThreadLocal<Boolean>(); public Object doLog(ProceedingJoinPoint jp) throws Throwable { Boolean isStart = startLocal.get(); // 做源頭標記 if (isStart == null) { startLocal.set(true); if (logger.isDebugEnabled()) { LogUtils.debug(logger, "----------開始進入全局日志記錄攔截器-------------"); } } try { // 執行目標方法 return jp.proceed(); } catch (Throwable e) { if (isStart == null) { logger.warn("業務執行出現未知異常:", e); } throw e; } finally { if (isStart == null) { startLocal.remove(); } } } }
日志攔截器的配置
配置攔截器,配置切面作用的范圍的表達式
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <aop:aspectj-autoproxy proxy-target-class="true"/> <bean id="log_Interceptor" class="com.iplatform.common.interceptor.LogInterceptor"/> <aop:config> <aop:aspect order="5" id="log_interceptor_aspect" ref="log_Interceptor"> <aop:pointcut id="log_interceptor_pointcut" expression="execution(* com.tem.*.service..*.*(..)) || execution(* com.tem..*.action.*.*(..)) || execution(* com.tem..*.*Controller.*(..))"/> <aop:around method="doLog" pointcut-ref="log_interceptor_pointcut"/> </aop:aspect> </aop:config> </beans>
知識點擴展
Spring Aop
AOP(Aspect Oriented Programming)既面向切面編程。解決面向對象編程(OOP)所缺乏的橫向邏輯處理的部分。例如每個方法都需要的對日志的支持,對事物的處理,對異常的處理等。這種散落在各處的重復邏輯的代碼被稱為橫切(cross cutting)。AOP剖解開封裝的對象內部,並將那些影響了多個類的公共行為封裝到一個可重用的模塊,並將其命名為切面(Aspect)。
核心概念
-
橫切關注點
對那些方法繼續攔截,攔截后怎么處理,這些關注點稱之為橫切關注點
-
切面(aspect)
類是對物理特征的抽象,切面就是對橫切關注點的抽象
-
連接點(joinpoint)
被攔截到的點,因為Spring只支持方法類型的連接點,所以在Spring中連接點指的就是被攔截到的方法,實際上連接點還可以是字段或者構造器
-
切入點(pointcut)
對連接點進行攔截的定義,支持execution 表達式
-
通知(advice)
所謂通知指的就是指攔截到連接點之后要執行的代碼,通知分為 前置、后置、異常、最終、環繞 通知五類
-
目標對象
代理的目標對象
-
織入(weave)
將切面應用到目標對象並導致代理對象創建的過程
-
引入(introduction)
在不修改代碼的前提下,引入可以在運行期為類動態地添加一些方法或字段