亚洲免费人人妻人人,cao78在线视频,福建一级毛片,91精品视频免费观看,高清另类图片操逼,日本特黄特色大片免费看,超碰欧美人人澡曰曰澡夜夜泛

基于AOP的日志調(diào)試 -管理資料

管理資料 時(shí)間:2019-01-01 我要投稿
【m.msguai.com - 管理資料】

   

斷點(diǎn) vs 日志

    斷點(diǎn)是我們?nèi)粘i_發(fā)最為常見和高效的調(diào)試手段, 相比較輸入日志它給予更多的狀態(tài)信息和靈活的觀察角度, 但斷點(diǎn)調(diào)試是有前提和局限的.

    需要一個(gè)界面友好, 功能強(qiáng)大的IDE,

    比較適合于在單機(jī)的開發(fā)環(huán)境中進(jìn)行.

    企業(yè)應(yīng)用開發(fā)中, 我們常常會(huì)遇到無法斷點(diǎn)調(diào)試的窘境, 例如:

    這個(gè)異常僅在生產(chǎn)環(huán)境出現(xiàn), 開發(fā)環(huán)境里無法重現(xiàn);

    存在外部系統(tǒng)依賴, 開發(fā)環(huán)境無法模擬等.

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

Print vs Logging

    簡單點(diǎn)的話, 我們用

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

    就是因?yàn)檫^于簡單, 當(dāng)需要更多信息(如線程, 時(shí)間等), 或是定義輸出模式和形式就需要編寫更多代碼, 于是我們有了Log4j.

為什么要基于AOP

    Log4j挺好用的, 只是與System.out.print一樣, 在代碼中隨處可見, 但卻沒有業(yè)務(wù)價(jià)值.

    更令人頭痛的是, 并非每次我們都有足夠的經(jīng)驗(yàn)告訴自己應(yīng)該在哪里添加這些語句, 以致于調(diào)試中不斷的因?yàn)檎{(diào)正它們的在代碼中的位置, 而反復(fù)編譯 – 打包 – 發(fā)布系統(tǒng). 這種體力活, 太沒藝術(shù)感了, 囧!

    換而言之, 我們會(huì)希望:

    將Logging剝離于業(yè)務(wù)之外, 讓代碼更易于維護(hù),

    無需重新編譯,甚至能夠運(yùn)行時(shí), 可調(diào)整輸出日志的位置.

    AOP完全可以幫助我們做到上述兩點(diǎn).

    這完全不是什么新鮮觀點(diǎn), 這在任何介紹AOP文章中, 都會(huì)提到Logging是其最典型的應(yīng)用場景.

    所以這兒將基于Guice, 討論如何實(shí)現(xiàn)一個(gè)非侵入式的, 且能無需重新編譯即可調(diào)正Logging位置的簡單示例.

一個(gè)基于Guice的示例

    我曾經(jīng)用過一個(gè)叫Log4E的Eclipse插件, 它可根據(jù)我們預(yù)先的配置, 自動(dòng)的為我們?cè)诰帉懙拇a中插入logging的語句, 如方法調(diào)用的進(jìn)口和出口:

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);  }}

    從上例不難發(fā)現(xiàn), 我們?cè)谡{(diào)試過程中, 往往會(huì)通過一個(gè)方法的進(jìn)入或退出的狀態(tài)(參數(shù), 返回值或異常)來分析問題出在什么地方. 那么, 借助MethodInterceptor我們可以這樣做:

Logging

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

    接下來, 我們需要配置這個(gè) , 并向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());  }}

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

    等等, 好像忘了去實(shí)現(xiàn)如何配置日志輸出的位置. 好吧, 這個(gè)其實(shí)很簡單:

配置Logging位置

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

    bindInterceptor方法的第一個(gè)參數(shù)定義了 將匹配所有類, 第二個(gè)參數(shù)定義了 將匹配一個(gè)類所有方法. 那么, 我們要做的僅僅是通過外部參數(shù)調(diào)整這兩個(gè)參數(shù)就可以啦. 這兒就演示一個(gè)用正則表達(dá)式匹配要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();  }}

    可惜這種方法不能在運(yùn)行時(shí)調(diào)整, 但這也是可以實(shí)現(xiàn)的.

運(yùn)行時(shí)配置Logging位置

    還是以用正則表達(dá)式匹配要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 方法, 參數(shù)與返回值        log(invocation.getMethod(), invocation.getArguments(), result);      return result;    } catch (Throwable throwable) {      if (methodName.matches(regex))        // logging 方法, 參數(shù)與異常        error(invocation.getMethod(), invocation.getArguments(), throwable);      throw throwable;    }  }}

    而后可借助JMX動(dòng)態(tài)調(diào)整regex的值, 來實(shí)現(xiàn)運(yùn)行時(shí)的配置. 當(dāng)然, 肯定還會(huì)有其它更好的方法, 如果你知道了不妨分享一下.

小結(jié)

    本文僅以Guice為例討論如何改進(jìn)我們?nèi)粘i_發(fā)中調(diào)試的問題, 其實(shí)這在Spring應(yīng)用也同樣能夠?qū)崿F(xiàn)的, 甚至其它應(yīng)用AOP的場景都是可行的.

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

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

最新文章
推薦文章