2011-08-22 9 views
5

Estoy usando Spring 3.0.5 con un aspecto Around.Spring Aspect falla cuando se invoca el punto de unión en un nuevo hilo

El aspecto @Around funciona perfectamente. La expresión de AOP se dirige a las interfaces de un puñado de frijoles.

El aspecto ejecuta una lógica antes y después de la invocación:

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

No es gran cosa.

Ahora, intento crear otro aspecto que arroje una excepción si el método interceptado lleva demasiado tiempo.

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

Cuando ejecuto el código sólo con este aspecto aplicado consigo la siguiente excepción:

java.lang.RuntimeException: java.lang.IllegalStateException: No MethodInvocation encontrado: Comprobar que un AOP la invocación está en progreso, y que ExposeInvocationInterceptor se encuentra en la cadena del interceptor.

Desde el Spring documentation leí: "Clase ExposeInvocationInterceptor

interceptor que expone la MethodInvocation actual como un objeto local de subprocesos"

Parece que el objetivo se perdió porque, básicamente, comienzo un nuevo hilo y el nuevo hilo no tiene acceso al hilo local. ¿Hay alguna manera de resolver este problema o un mejor enfoque?

Gracias

Respuesta

1

La solución fue bastante trivial. El aspecto que verifica cuánto tiempo tarda un método debe ser el último en la "cadena" de aspectos. He utilizado la anotación @Order en el aspecto para que sea el último en ser ejecutado.

Eso hizo el truco.

Si el aspecto no es el último en ejecutarse, el nuevo subproceso no puede acceder a la variable ThreadLocal que contiene la clase ExposeInvocationInterceptor.

0

Usted podría intentar interrumpir el flujo actual desde otro hilo, si la llamada pjp.proceed() es susceptible de interrupción. P.ej. su aspecto se parece 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? 
    } 

donde la clase interruptor sería algo así como:

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

¡Lo intentaré! Gracias –

Cuestiones relacionadas