Spring Aspect gagal ketika titik gabungan dipanggil di thread baru

Saya menggunakan Spring 3.0.5 dengan aspek Around.

Aspek @Around berfungsi dengan sempurna. Ekspresi AOP menargetkan antarmuka sekelompok kacang.

Aspek ini menjalankan beberapa logika sebelum dan sesudah pemanggilan:

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

Bukan masalah besar.

Sekarang, saya mencoba membuat aspek lain yang memberikan pengecualian jika metode intersepsi memakan waktu terlalu lama.

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

Ketika saya mengeksekusi kode dengan hanya menerapkan aspek ini, saya mendapatkan pengecualian berikut:

java.lang.RuntimeException: java.lang.IllegalStateException: Tidak ditemukan MethodInvocation: Periksa apakah pemanggilan AOP sedang berlangsung, dan ExposeInvocationInterceptor berada dalam rantai interseptor.

Dari Dokumentasi musim semi Saya membaca:

"Kelas ExposeInvocationInterceptor

Interceptor yang mengekspos MethodInvocation saat ini sebagai objek thread-lokal."

Jadi sepertinya targetnya hilang karena pada dasarnya saya memulai thread baru dan thread baru tersebut tidak memiliki akses ke thread lokal. Apakah ada cara untuk mengatasi masalah ini atau pendekatan yang lebih baik?

Terima kasih


person Luciano Fiandesio    schedule 22.08.2011    source sumber


Jawaban (2)


Solusinya cukup sepele. Aspek yang memeriksa berapa lama waktu yang dibutuhkan suatu metode harus menjadi yang terakhir dalam "rantai" aspek. Saya telah menggunakan anotasi @Order pada Aspek untuk menjadikannya yang terakhir dieksekusi.

Itu berhasil.

Jika Aspect bukan yang terakhir dieksekusi, Thread baru tidak dapat mengakses variabel ThreadLocal yang berisi kelas ExposeInvocationInterceptor.

person Luciano Fiandesio    schedule 23.08.2011

Anda dapat mencoba menginterupsi thread saat ini dari thread lain, jika panggilan pjp.proceed() dapat diinterupsi. Misalnya. aspek Anda terlihat seperti:

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

di mana kelas Interrupter akan menjadi seperti:

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();
        }
    }
}
person artbristol    schedule 22.08.2011