2011-08-22 9 views
5

Sto usando Spring 3.0.5 con un aspetto Around.Spring Aspect non riesce quando il punto di join viene richiamato nella nuova discussione

L'aspetto @Around funziona perfettamente. L'espressione AOP ha come target le interfacce di un gruppo di bean.

L'aspetto esegue una logica prima e dopo l'invocazione:

@Around(...) 
    public Object monitor(ProceedingJoinPoint pjp) throws Throwable { 
     // some code 
     Obj o = pjp.proceed(); 
     // some code 
    } 

un grosso problema.

Ora, sto cercando di creare un altro aspetto che genera un'eccezione se il metodo intercettato impiega troppo tempo.

private static ExecutorService executor = Executors.newCachedThreadPool(); 

@Around(...) 
public Object monitor(ProceedingJoinPoint pjp) throws Throwable { 

Object obj = null; 

Callable<Object> task = new Callable<Object>() { 
    public Object call() { 
     return pjp.proceed(); 
    } 
}; 
Future<Object> future = executor.submit(task); 
try { 
    obj = future.get(timeout, TimeUnit.MILLISECONDS); 
} catch (TimeoutException ex) { 
    ... 
} catch (InterruptedException e) { 
    // we ignore this one... 
} catch (ExecutionException e) { 
    throw e.getCause(); // rethrow any exception raised by the invoked method 
} finally { 
    future.cancel(true); // may or may not desire this 
} 

return obj; 
} 

Quando eseguo il codice con solo questo aspetto applicato ottengo la seguente eccezione:

java.lang.RuntimeException: java.lang.IllegalStateException: No MethodInvocation trovato: Verificare che un AOP è in corso l'invocazione, e che ExposeInvocationInterceptor si trova nella catena dell'intercettore.

Dal Spring documentation ho letto: "Classe ExposeInvocationInterceptor

Interceptor che espone il MethodInvocation corrente come oggetto thread-local"

Quindi sembra che il bersaglio si sia perso perché fondamentalmente inizio un nuovo thread e il nuovo thread non ha accesso al thread locale. C'è un modo per risolvere questo problema o un approccio migliore?

Grazie

risposta

1

la soluzione è stata abbastanza banale. L'Aspetto che controlla quanto tempo impiega un metodo deve essere l'ultimo nella "catena" degli aspetti. Ho usato l'annotazione @Order sull'aspetto per renderla l'ultima ad essere eseguita.

Questo ha funzionato.

Se l'aspetto non è l'ultimo da eseguire, la nuova discussione non è in grado di accedere alla variabile ThreadLocal che contiene la classe ExposeInvocationInterceptor.

0

Si potrebbe provare a interrompere il thread corrente da un altro thread, se la chiamata pjp.proceed() è suscettibile di interruzione. Per esempio. il vostro aspetto assomiglia a:

new Interrupter(Thread.currentThread()).start(); 
    // Following call will get interrupted if it takes too long 
    try { 
     return pjp.proceed(); 
    } catch (InterruptedException ex) { 
     // do something? 
    } 

dove la classe Interruttore sarebbe qualcosa di simile:

static class Interrupter extends Thread { 

    private final Thread other; 

    Interrupter(final Thread other) { 
     this.other = other; 
    } 

    @Override 
    public void run() { 
     try { 
      Thread.sleep(500); // or whatever your timeout is 
     } catch (final InterruptedException e) { 
      e.printStackTrace(); 
     } 
     if (other.isAlive()) { 
      other.interrupt(); 
     } 
    } 
} 
+0

Provalo! Grazie –

Problemi correlati