歡迎光臨
每天分享高質量文章

Spring MVC舊專案的日誌埋點

一、HTTP介面切麵

1.web容器和應用容器
IoC是Spring框架中的核心概念之一,如果要在Spring MVC中使用Spring的這一特性,也需要構建類似的容器。在Spring MVC中,主要透過web.xml進行Web相關的配置,例如配置DispatchServlet,以便應對url請求到具體的controller方法的對映。當DispatcherServlet啟動的時候,它會建立一個對應的web應用背景關係,負責載入web相關的元件,例如控制器、檢視解析器以及處理器對映。在web.xml中,還有個常用配置:ContextLoaderListener,會建立一個Spring應用背景關係,用於載入應用中的其他bean,例如各種Service、各種資料庫訪問層。借用官方檔案-mvc servlet的一張圖,可以看出,由ContextLoaderListener啟動的容器為Root容器(父容器)、由DispatcherServlert啟動的容器為Web容器(子容器),並且,子容器可以看到父容器中的bean,反之則不可。正是因為這個原因,在Controller層應用AOP技術的時候,要註意兩點:(1)xxx-servlet.xml中的component-scan配置,要確定只掃描web元件、yyyyApplicationContext.xml中的component-scan配置,要排除掉web元件;(2)在xxx-servlet.xml中配置AOP,啟動自動代理的配置為: proxy-target-class="true"/>,使用基於類的代理機制——CGLIB。

2.基於註解的AOP應用
我這裡所謂基於註解的AOP技術,是指利用自定義註解標註要織入的切點,這種方式比較靈活,可以對指定介面中的某幾個方法進行切麵。例如,在這次處理日誌埋點的需求中,我只給公開的介面加了註解:

  1. import java.lang.annotation.*;

  2. @Target(ElementType.METHOD)

  3. @Retention(RetentionPolicy.RUNTIME)

  4. @Documented

  5. public @interface BizLogAnnotation {

  6.    String description() default "";

  7. }

然後在xxxAspect中給出如下切點定義即可:

  1. @Aspect

  2. @Component

  3. public class DubboLogAspect {

  4.    @Pointcut(value = "@annotation(com.xxxx.dubbo.log.BizLogAnnotation)")

  5.    public void hsfMethod() { }

  6.    ……

  7. }

3.從切點JoinPoint獲取註解中的描述資訊,該方法參考自一文,程式碼如下:

  1. public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {  

  2.         String targetName = joinPoint.getTarget().getClass().getName();  

  3.         String methodName = joinPoint.getSignature().getName();  

  4.         Object[] arguments = joinPoint.getArgs();  

  5.         Class targetClass = Class.forName(targetName);  

  6.         Method[] methods = targetClass.getMethods();  

  7.         String description = "";  

  8.         for (Method method : methods) {  

  9.             if (method.getName().equals(methodName)) {  

  10.                 Class[] clazzs = method.getParameterTypes();  

  11.                 if (clazzs.length == arguments.length) {  

  12.                     description = method.getAnnotation(SystemControllerLog.class).description();  

  13.                     break;  

  14.                 }  

  15.             }  

  16.         }  

  17.         return description;  

  18.     }  

二、RPC服務介面切麵

  1. 普通Service的AOP

三、Log4j日誌配置

  1. 配置依賴,log4j + slf4j依賴

  2. 配置log4j.properties

  3. 修改程式碼中的Logger

四、補充資料

  1. 在閱讀官方檔案的時候,發現官方檔案中也有對Controller AOP的闡述。

In some cases a controller may need to be decorated with an AOP proxy at runtime. One example is if you choose to have @Transactional annotations directly on the controller. When this is the case, for controllers specifically, we recommend using class-based proxying. This is typically the default choice with controllers. However if a controller must implement an interface that is not a Spring Context callback (e.g. InitializingBean, *Aware, etc), you may need to explicitly configure class-based proxying. For example with, change to.

  1. 當AOP遇到雙背景關係

  2. 為什麼對Controller應用AOP的時候必須使用class-based的代理機制呢?這又涉及Spring中的兩種代理機制:Java Proxy和CGLIB,Java Proxy要求被代理的類必須實現某個介面;CGLIB則屬於基於子類的代理機制。參考What is the difference between JDK dynamic proxy and CGLib?

贊(0)

分享創造快樂