2013-11-03 17 views
6

Có thể tôi không suy nghĩ đủ hoặc câu trả lời thực sự khó nắm bắt. Kịch bản nhanh (Hãy thử mã. Nó biên dịch).CGLIB không thể chặn các phương thức trong một siêu lớp/siêu bề mặt

Xem xét một giao diện cũ

public interface LegacyInterfaceNoCodeAvailable{ 
    void logInfo(String message); 
} 

Các xem xét việc thực hiện di sản của giao diện trên

public abstract class LegacyClassNoCodeAvailable implements LegacyInterfaceNoCodeAvailable{ 

    public abstract void executeSomething(); 

    public void rockItOldSchool(){ 
     logInfo("bustin' chops, old-school style"); 
    } 

    @Override 
    public void logInfo(String message){ 
     System.out.println(message); 
    } 
} 

Bây giờ tôi đi vào như người đầy tham vọng này và viết một lớp cho hệ thống một 'mới' nhưng chạy bên trong khung 'Legacy', do đó tôi phải mở rộng lớp cơ sở cũ.

public class lass SpankingShiny extends LegacyClassNoCodeAvailable{ 

    public void executeSomething(){ 
     rockItOldSchool(); 
     logInfo("I'm the King around here now"); 
     System.out.println("this new stuff rocks!!"); 
    } 
} 

Tất cả mọi thứ hoạt động tuyệt vời, giống như bạn mong chờ:

SpankingShiny shiny = new SpankingShiny(); 
shiny.executeSomething(); 

Lợi suất trên mã (như dự kiến):

bustin' chops, old-school style 
I'm the King around here now 
this new stuff rocks!! 

Bây giờ khi bạn có thể thấy, 'System. out.println() 'trung thành in kết quả mong muốn. Nhưng tôi muốn thay thế 'System.out.println()' bằng trình ghi nhật ký.

Vấn đề:

Tôi không thể có proxy cglib chặn các phương pháp để 'logInfo (string)' và có nó in ra thông điệp của tôi mong muốn thông qua một logger (I have done cấu hình đăng nhập ngay bên cạnh đường). Đó là lời gọi phương thức 'rõ ràng' không nhấn proxy.

Code:

public class SpankingShinyProxy implements MethodInterceptor{ 

    private SpankingShiny realShiny; 
    private final Logger logger = Logger.getLogger(SpankingShinyProxy.class); 

    public SpankingShinyProxy(SpankingShiny realShiny) { 
     super(); 
     this.realShiny = realShiny; 
    } 

    @Override 
    public Object intercept(Object proxyObj, Method proxyMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable { 
     String methodName = proxyMethod.getName(); 
     if("logInfo".equals(methodName)){ 
      logger.info(methodParams[0]); 
     } 
     return proxyMethod.invoke(realShiny, methodParams); 
    } 

    public static SpankingShiny createProxy(SpankingShiny realObj){ 
     Enhancer e = new Enhancer(); 
     e.setSuperclass(realObj.getClass()); 
     e.setCallback(new SpankingShinyProxy(realObj)); 
     SpankingShiny proxifiedObj = (SpankingShiny) e.create(); 
     return proxifiedObj; 
    } 
} 

phương pháp chính:

public static void main(String... args) { 

     SpankingShiny shiny = new SpankingShiny(); 
     shiny.executeSomething(); 

     SpankingShiny shinyO = SpankingShinyProxy.createProxy(shiny); 
     shinyO.executeSomething(); 
    } 

Sản lượng mã trên (KHÔNG như mong đợi):

bustin' chops, old-school style 
I'm the King around here now 
this new stuff rocks!! 
bustin' chops, old-school style 
I'm the King around here now 
this new stuff rocks!! 

đâu sẽ Tôi được đi sai?

Cảm ơn!

Trả lời

1

Trước tiên, bạn may mắn là proxy của bạn không bị tấn công. Nếu bạn đang tham chiếu đến proxy thực sự trong phạm vi intercept, bạn sẽ kết thúc bằng một vòng lặp vô tận vì việc kích hoạt phương pháp phản xạ của bạn sẽ được gửi đi bởi cùng một SpankingShinyProxy. Lặp đi lặp lại.

Proxy không hoạt động vì bạn chỉ cần ủy quyền phương thức gọi executeSomething trên proxy của bạn cho một số đối tượng không được đáp ứng. Bạn không được sử dụng realObj. Tất cả các cuộc gọi phương thức phải được gửi đi bởi proxy của bạn, cũng là những cuộc gọi phương thức được gọi bởi phải nhấn chính proxy đó!

Thay đổi dòng cuối cùng trong phương thức intercept của bạn thành methodProxy.invokeSuper(proxyObj, args). Sau đó, xây dựng đối tượng của bạn bằng cách sử dụng Enhancer. Nếu hàm tạo của bạn cho SpankingShiny không cần đối số, hãy gọi create mà không có bất kỳ đối số nào nếu không. Nếu không, hãy cung cấp các đối tượng bạn thường cung cấp cho hàm tạo theo phương thức create. Sau đó, chỉ sử dụng đối tượng mà bạn nhận được từ create và bạn tốt.

Nếu bạn muốn biết thêm thông tin về cglib, bạn có thể muốn đọc bài viết trên blog này: http://mydailyjava.blogspot.no/2013/11/cglib-missing-manual.html

0

tôi đã cùng một vấn đề. Trong trường hợp của tôi, số realObj là một proxy (một Spring Bean - a @Component).

Vì vậy, những gì tôi phải làm là thay đổi một phần .setSuperClass() trong:

Enhancer e = new Enhancer(); 
e.setSuperclass(realObj.getClass()); 
e.setCallback(new SpankingShinyProxy(realObj)); 
SpankingShiny proxifiedObj = (SpankingShiny) e.create(); 

tôi đã thay đổi:

e.setSuperclass(realObj.getClass()); 

Để:

e.setSuperclass(realObj.getClass().getSuperClass()); 

này làm việc bởi vì, như đã nói, realObj.getClass() là một proxy CGLIB, và phương thức đó đã trả về một clas điên-CGLIB tạo ra s, chẳng hạn như a.b.c.MyClass$$EnhancerBySpringCGLIB$$1e18666c. Khi tôi thêm .getSuperClass(), nó sẽ trả lại lớp mà nó đáng lẽ phải quay trở lại ngay từ đầu.

Các vấn đề liên quan