2016-08-20 66 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