精品一区二区中文在线,无遮挡h肉动漫在线观看,国产99视频精品免视看9,成全免费高清大全

基于AOP的日志調試 -管理資料

管理資料 時間:2019-01-01 我要投稿
【salifelink.com - 管理資料】

   

斷點 vs 日志

    斷點是我們日常開發最為常見和高效的調試手段, 相比較輸入日志它給予更多的狀態信息和靈活的觀察角度, 但斷點調試是有前提和局限的.

    需要一個界面友好, 功能強大的IDE,

    比較適合于在單機的開發環境中進行.

    企業應用開發中, 我們常常會遇到無法斷點調試的窘境, 例如:

    這個異常僅在生產環境出現, 開發環境里無法重現;

    存在外部系統依賴, 開發環境無法模擬等.

    這迫使我們不得不回到日志調試的老路子上來.

Print vs Logging

    簡單點的話, 我們用

System.out.println("debug infomation");

    就是因為過于簡單, 當需要更多信息(如線程, 時間等), 或是定義輸出模式和形式就需要編寫更多代碼, 于是我們有了Log4j.

為什么要基于AOP

    Log4j挺好用的, 只是與System.out.print一樣, 在代碼中隨處可見, 但卻沒有業務價值.

    更令人頭痛的是, 并非每次我們都有足夠的經驗告訴自己應該在哪里添加這些語句, 以致于調試中不斷的因為調正它們的在代碼中的位置, 而反復編譯 – 打包 – 發布系統. 這種體力活, 太沒藝術感了, 囧!

    換而言之, 我們會希望:

    將Logging剝離于業務之外, 讓代碼更易于維護,

    無需重新編譯,甚至能夠運行時, 可調整輸出日志的位置.

    AOP完全可以幫助我們做到上述兩點.

    這完全不是什么新鮮觀點, 這在任何介紹AOP文章中, 都會提到Logging是其最典型的應用場景.

    所以這兒將基于Guice, 討論如何實現一個非侵入式的, 且能無需重新編譯即可調正Logging位置的簡單示例.

一個基于Guice的示例

    我曾經用過一個叫Log4E的Eclipse插件, 它可根據我們預先的配置, 自動的為我們在編寫的代碼中插入logging的語句, 如方法調用的進口和出口:

public int sum(int a, int b){  if (logger.isDebugEnabled()){    logger.debug("sum - start : a is " + a + ", b is " + b);  }  int result = a + b;  if (logger.isDebugEnabled()){    logger.debug("sum - end : return is " + result);  }}

    從上例不難發現, 我們在調試過程中, 往往會通過一個方法的進入或退出的狀態(參數, 返回值或異常)來分析問題出在什么地方. 那么, 借助MethodInterceptor我們可以這樣做:

Logging

public class LoggingInterceptor implements MethodInterceptor {  @Override  public Object invoke(MethodInvocation invocation) throws Throwable {    try {      Object result = invocation.proceed();      // logging 方法, 參數與返回值      log(invocation.getMethod(), invocation.getArguments(), result);      return result;    } catch (Throwable throwable) {      // logging 方法, 參數與異常      error(invocation.getMethod(), invocation.getArguments(), throwable);      throw throwable;    }  }}

    接下來, 我們需要配置這個 , 并向Guice聲明它.

public class LoggingModule extends AbstractModule {  @Override  public void configure() {    bindInterceptor(Matchers.any(), Matchers.any(), new LoggingInterceptor());  }}public class Main {  public static void main(String[] args) {    Injector injector = Guice.createInjector(new BusinessModule(), new LoggingModule());  }}

    很簡單, 不是嗎? 這樣我們的業務模塊的代碼完全不用編寫輸出日志的代碼, 只需要在創建Injector的時候加入LoggingModule就可以了.

    等等, 好像忘了去實現如何配置日志輸出的位置. 好吧, 這個其實很簡單:

配置Logging位置

bindInterceptor(Matchers.any(), Matchers.any(), new LoggingInterceptor());

    bindInterceptor方法的第一個參數定義了 將匹配所有類, 第二個參數定義了 將匹配一個類所有方法. 那么, 我們要做的僅僅是通過外部參數調整這兩個參數就可以啦. 這兒就演示一個用正則表達式匹配要Logging的方法的例子:

public class MethodRegexMatcher extends AbstractMatcher<Method> {  private final Pattern pattern = Pattern.compile(System.getProperty("logging.method.regex", "*"));  @Override  public boolean matches(Method method) {    return pattern.matcher(method.getName()).matches();  }}

    可惜這種方法不能在運行時調整, 但這也是可以實現的.

運行時配置Logging位置

    還是以用正則表達式匹配要Logging的方法為例:

public class LoggingInterceptor implements MethodInterceptor {  private String regex = "*";      public void setMethodRegex(String regex){    this.regex = regex;  }  @Override  public Object invoke(MethodInvocation invocation) throws Throwable {    String methodName = invocation.getMethod().getName();        try {      Object result = invocation.proceed();                  if (methodName.matches(regex))        // logging 方法, 參數與返回值        log(invocation.getMethod(), invocation.getArguments(), result);      return result;    } catch (Throwable throwable) {      if (methodName.matches(regex))        // logging 方法, 參數與異常        error(invocation.getMethod(), invocation.getArguments(), throwable);      throw throwable;    }  }}

    而后可借助JMX動態調整regex的值, 來實現運行時的配置. 當然, 肯定還會有其它更好的方法, 如果你知道了不妨分享一下.

小結

    本文僅以Guice為例討論如何改進我們日常開發中調試的問題, 其實這在Spring應用也同樣能夠實現的, 甚至其它應用AOP的場景都是可行的.

    拓展開來, 不僅是Logging, 說不定驗證(測試)也是可行的呢!

    有句話不是這樣說的嗎, “思想有多遠, 我們就能走多遠!”

最新文章
推薦文章