2016-08-20 80 views
0

我有MyClassAopLogger。如果doSomething發生異常,則迭代停止。投擲後彈簧AOP繼續迭代

如何防止退出logAround並繼續與下一個主機? ObjectlogAround返回有什麼好處,我們可以用這個Object做什麼?

class MyClass{ 
    void check() throws Exception {  
     Iterator<Host> iter_host = configReader.getHostMap().values().iterator();  
     while (iter_host.hasNext()) {    
      Host host = (Host) iter_host.next(); 
      host.doSomething(); 
     } 
    } 
    void doSomething(){} //Exception 
} 

class AopLogger {  
    @Around("execution(* com.mypackage..*.*(..))") 
    Object logAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ 
     return proceedingJoinPoint.proceed(); 
    } 
} 
+0

你沒有提供足夠的信息;如果連接點在doSomething方法中(假設它是公共的),那麼它應該足夠讓try catch塊返回proceedingJoinPoint.proceed()。 「什麼對你有好處......」當你進入doSomething時,以及方法何時返回,你可能會記錄下來;其實很奇怪,在代碼中缺少這個。 –

+0

當我把try catch塊返回proceedingJoinPoint.proceed()迭代結束,應用程序退出。當我把try catch塊放在host.doSomething()周圍時,迭代繼續,但是我不能在logAround – user2683906

+0

中記錄任何東西,首先找出連接點是什麼:在你的IDE中放置一個斷點,返回proceedingJoinPoint.proceed()和檢查ProceedingJoinPoint的各個領域 - 你應該看到哪個方法被攔截。嘗試從那裏推理。 –

回答

1

首先,你的方面類應該有一個@Aspect註釋。其次,如果你想使用Spring AOP而不是完整的AspectJ,你的方面和所有的目標類都應該是Spring @Component s。

話雖如此,這裏是一個小樣本。我用普通的AspectJ創建了它,但Spring AOP中的方面代碼應該是相同的。

Helper類使代碼編譯並運行:

package de.scrum_master.app; 

import java.util.Random; 

public class Host { 
    private static final Random RANDOM = new Random(); 

    private String name; 

    public Host(String name) { 
     this.name = name; 
    } 

    public void doSomething() { 
     if (RANDOM.nextBoolean()) 
      throw new RuntimeException("oops!"); 
    } 

    @Override 
    public String toString() { 
     return "Host(name=" + name + ")"; 
    } 
} 
package de.scrum_master.app; 

import java.util.HashMap; 
import java.util.Map; 

public class ConfigReader { 
    private Map<Integer, Host> hostMap = new HashMap<>(); 

    public ConfigReader() { 
     hostMap.put(1, new Host("mercury")); 
     hostMap.put(2, new Host("venus")); 
     hostMap.put(3, new Host("earth")); 
     hostMap.put(4, new Host("mars")); 
    } 

    public Map<Integer, Host> getHostMap() { 
     return hostMap; 
    } 
} 

驅動程序:

我不喜歡Iterator這是從老版本的JDK的遺物,所以我用更現代的Java風格for循環取而代之。

package de.scrum_master.app; 

class MyClass { 
    private ConfigReader configReader = new ConfigReader(); 

    void check() throws Exception { 
     for (Host host : configReader.getHostMap().values()) { 
      System.out.println(host); 
      host.doSomething(); 
     } 
    } 

    public static void main(String[] args) throws Exception { 
     new MyClass().check(); 
    } 
} 

看點與切入點/建議做記錄和異常在同一時間處理:

另外請注意,我的意見在代碼的最後一刻。

package de.scrum_master.aspect; 

import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Aspect; 

@Aspect 
public class AopLogger { 
    private static final InheritableThreadLocal<String> indent = new InheritableThreadLocal<String>() { 
     @Override 
     protected String initialValue() { 
      return ""; 
     } 
    }; 

    @Around("execution(* de.scrum_master.app..*(..)) && !execution(* toString())") 
    public Object logAround(ProceedingJoinPoint thisJoinPoint) throws Throwable { 
     Object result = null; 
     System.out.println(indent.get() + ">> " + thisJoinPoint); 
     try { 
      indent.set(indent.get() + " "); 
      result = thisJoinPoint.proceed(); 
      indent.set(indent.get().substring(2)); 
     } catch (Exception e) { 
      System.out.println(indent.get() + "Caught exception: " + e); 
      indent.set(indent.get().substring(2)); 
     } 
     System.out.println(indent.get() + "<< " + thisJoinPoint); 

     // Attention: If a method with a caught exception does not have 'void' 
     // return type, we return a (probably unexpected) result of 'null' here. 
     // So maybe we should not catch all execptions but rather pick more 
     // specific joinpoints where we are sure we can cleanly handle the 
     // corresponding exceptions. 
     return result; 
    } 
} 

控制檯日誌:

>> execution(void de.scrum_master.app.MyClass.main(String[])) 
    >> execution(void de.scrum_master.app.MyClass.check()) 
    >> execution(Map de.scrum_master.app.ConfigReader.getHostMap()) 
    << execution(Map de.scrum_master.app.ConfigReader.getHostMap()) 
Host(name=mercury) 
    >> execution(void de.scrum_master.app.Host.doSomething()) 
     Caught exception: java.lang.RuntimeException: oops! 
    << execution(void de.scrum_master.app.Host.doSomething()) 
Host(name=venus) 
    >> execution(void de.scrum_master.app.Host.doSomething()) 
    << execution(void de.scrum_master.app.Host.doSomething()) 
Host(name=earth) 
    >> execution(void de.scrum_master.app.Host.doSomething()) 
     Caught exception: java.lang.RuntimeException: oops! 
    << execution(void de.scrum_master.app.Host.doSomething()) 
Host(name=mars) 
    >> execution(void de.scrum_master.app.Host.doSomething()) 
     Caught exception: java.lang.RuntimeException: oops! 
    << execution(void de.scrum_master.app.Host.doSomething()) 
    << execution(void de.scrum_master.app.MyClass.check()) 
<< execution(void de.scrum_master.app.MyClass.main(String[])) 

第二個方面的變體分離異常處理記錄:

package de.scrum_master.aspect; 

import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Aspect; 

@Aspect 
public class AopLogger { 
    private static final InheritableThreadLocal<String> indent = new InheritableThreadLocal<String>() { 
     @Override 
     protected String initialValue() { 
      return ""; 
     } 
    }; 

    @Around("execution(* de.scrum_master.app..*(..)) && !execution(* toString())") 
    public Object logAround(ProceedingJoinPoint thisJoinPoint) throws Throwable { 
     System.out.println(indent.get() + ">> " + thisJoinPoint); 
     try { 
      indent.set(indent.get() + " "); 
      Object result = thisJoinPoint.proceed(); 
      indent.set(indent.get().substring(2)); 
      System.out.println(indent.get() + "<< " + thisJoinPoint); 
      return result; 
     } catch (Exception e) { 
      indent.set(indent.get().substring(2)); 
      System.out.println(indent.get() + "<< " + thisJoinPoint); 
      throw e; 
     } 
    } 

    @Around("execution(void de.scrum_master.app.Host.doSomething())") 
    public void handleException(ProceedingJoinPoint thisJoinPoint) throws Throwable { 
     try { 
      thisJoinPoint.proceed(); 
     } catch (Exception e) { 
      System.out.println(indent.get() + "Caught exception: " + e); 
     } 
    } 
} 

日誌輸出保持不變,但這次的異常處理是在一個更精確的切入點單獨建議。日誌建議只關注日誌記錄(如果不是正確的縮進,甚至不需要嘗試捕獲)。異常處理建議只做自己的工作。

隨意問後續問題。

+0

謝謝,我認爲問題出在Apache BasicDataSource上。方法dosomething創建一個jdbc池。如果主機不可訪問,check()方法結束。當我把try(catch)塊中的check()工作。我正在嘗試另一種方式,現在在runnable類中做同樣的事情,但不知道如何實現可以拋出異常的void run()方法。我的意思是無效運行()拋出異常 – user2683906