2016-08-20 6 views
0

У меня есть MyClass и AopLogger. Итерация прекращается, если исключение имеет doSomething.Весна АОП продолжает итерацию после метания

Как предотвратить выход в logAround и продолжить со следующего хозяина? И что такое Object, возвращаемое logAround хорошо для, что мы можем сделать с этим 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 block вокруг return continueJoinPoint.proceed(). «Что это хорошо для ...», вы можете войти в систему, когда вы входите в doSomething, и когда метод возвращается; на самом деле странно, что этого не хватает в вашем коде. –

+0

, когда я помещаю блок catch try вокруг return continueJoinPoint.proceed() завершает итерацию и завершает работу приложения. Когда я помещаю блок catch try на host.doSomething(), итерация продолжается, но я ничего не могу зарегистрировать в logAround – user2683906

+0

, сначала узнайте, что такое точка соединения: поместите контрольную точку в свою IDE при возврате continueJoinPoint.proceed() и проверьте различные области ProceedingJoinPoint - вы должны увидеть, какой метод перехвачен.Попытайтесь рассуждать оттуда. –

ответ

1

Во-первых, ваш класс аспект должен содержать аннотацию @Aspect. Во-вторых, если вы хотите использовать Spring AOP, а не полный AspectJ, ваш аспект и все целевые классы также должны быть весной @Component.

Сказав это, вот небольшой образец. Я создал его с простым 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); 
     } 
    } 
} 

Выход журнала остается неизменным, но на этот раз обработка исключений находится в отдельном совете с более точным pointcut. Совет по протоколированию заботится только о протоколировании (даже если бы не правильный отступ, ему даже не понадобился бы try-catch). Совет по обработке исключений выполняет только свою работу.

Не стесняйтесь спрашивать о последующих вопросах.

+0

Спасибо, я думаю, проблема связана с Apache BasicDataSource. Метод dosomething создает пул jdbc. Проверка метода() заканчивается, если хост недоступен. Когда я помещаю check() в try catch block, он работает. Я пытаюсь по-другому сделать то же самое в runnable классе, но не знаю, как реализовать метод void run(), который может вызывать исключения. Я имею в виду void run() throws Exception – user2683906

 Смежные вопросы

  • Нет связанных вопросов^_^