Spring Aspect ล้มเหลวเมื่อมีการเรียกใช้จุดรวมในเธรดใหม่

ฉันใช้ Spring 3.0.5 กับมุมมองแบบ Round

มุมมอง @Around ทำงานได้อย่างสมบูรณ์แบบ นิพจน์ AOP กำหนดเป้าหมายอินเทอร์เฟซของกลุ่มถั่ว

ด้านดำเนินการตรรกะบางอย่างก่อนและหลังการเรียกใช้:

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

ไม่ใช่เรื่องใหญ่.

ตอนนี้ ฉันกำลังพยายามสร้างอีกแง่มุมหนึ่งที่ทำให้เกิดข้อยกเว้น หากวิธีการสกัดกั้นใช้เวลานานเกินไป

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

เมื่อฉันรันโค้ดโดยใช้เฉพาะด้านนี้ ฉันจะได้รับข้อยกเว้นต่อไปนี้:

java.lang.RuntimeException: java.lang.IllegalStateException: ไม่พบ MethodInvocation: ตรวจสอบว่าการเรียกใช้ AOP อยู่ระหว่างดำเนินการ และ ExposeInvocationInterceptor อยู่ใน interceptor chain

จากเอกสาร Spring ฉันอ่านว่า:

"คลาส ExposeInvocationInterceptor

Interceptor ที่เปิดเผย MethodInvocation ปัจจุบันเป็นวัตถุ thread-local

ดูเหมือนว่าเป้าหมายจะหายไปเนื่องจากโดยพื้นฐานแล้วฉันเริ่มเธรดใหม่และเธรดใหม่ไม่สามารถเข้าถึงเธรดในเครื่องได้ มีวิธีแก้ไขปัญหานี้หรือแนวทางที่ดีกว่านี้หรือไม่?

ขอบคุณ


person Luciano Fiandesio    schedule 22.08.2011    source แหล่งที่มา


คำตอบ (2)


วิธีแก้ปัญหาค่อนข้างเล็กน้อย ด้านที่ตรวจสอบว่าวิธีการใช้เวลานานเท่าใดจะต้องเป็นด้านสุดท้ายใน "ห่วงโซ่" ของด้านต่างๆ ฉันใช้คำอธิบายประกอบ @Order บน Aspect เพื่อให้เป็นคำอธิบายประกอบสุดท้ายที่จะดำเนินการ

นั่นเป็นกลอุบาย

หาก Aspect ไม่ใช่สิ่งสุดท้ายที่จะดำเนินการ Thread ใหม่จะไม่สามารถเข้าถึงตัวแปร ThreadLocal ที่มีคลาส ExposeInvocationInterceptor

person Luciano Fiandesio    schedule 23.08.2011

คุณสามารถลองขัดจังหวะเธรดปัจจุบันจากเธรดอื่นได้ หากการเรียก pjp.proceed() สามารถตอบสนองต่อการขัดจังหวะได้ เช่น. แง่มุมของคุณดูเหมือนว่า:

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

โดยที่คลาส Interrupter จะเป็นดังนี้:

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