2013-11-03 12 views
6

Może być, nie myślę wystarczająco mocno lub odpowiedź jest naprawdę nieuchwytna. Szybki scenariusz (wypróbuj kod, który kompiluje).CGLIB nie jest w stanie przechwycić metod w superklasie/superinterfejsie

Rozważmy interfejsem Legacy

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

The rozważyć wdrożenie starszego interfejsu powyżej

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

Teraz wejdę jak tego ambitnego człowieka i pisze klasę dla systemu „nowego”, ale który działa w ramach "Legacy", dlatego muszę rozszerzyć starszą klasę bazową.

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!!"); 
    } 
} 

Wszystko działa świetnie, tak jak można się spodziewać:

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

Powyższe plony Code (zgodnie z oczekiwaniami):

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

teraz jak widać, „system. out.println() "wiernie drukuje żądaną wydajność. Ale chcę zastąpić "System.out.println()" loggerem.

Problem:

jestem w stanie mieć pełnomocnika CGLIB przechwycenia metody na „logInfo (String)” i go wydrukować mojego żądanej wiadomości przez rejestrator (Zrobiłem konfigurację rejestrowania przez prawo droga). Ta metoda "pozornie" nie trafia w proxy.

Kod:

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

metoda Main:

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

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

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

Powyższe plony kod (not as expected):

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!! 

Gdzie bym się nie tak?

Dzięki!

Odpowiedz

1

Po pierwsze, masz szczęście, że twoje proxy nie zostało trafione. Jeśli odwoływałeś się do rzeczywistego proxy w ciągu intercept, skończyłbyś z nieskończoną pętlą, ponieważ twoja metoda odbicia została wywołana przez to samo SpankingShinyProxy. Znowu i znowu.

Serwer proxy nie działa, ponieważ po prostu delegujesz wywołanie metody executeSomething na swoim proxy do jakiegoś nieproszonego obiektu. Nie wolno używać realObj. Wszystkie wywołania metod muszą być wysyłane przez serwer proxy, także te wywołania metody, które są wywoływane przez moszcz, muszą trafić samo proxy!

Zmień ostatnią linię w metodzie intercept na methodProxy.invokeSuper(proxyObj, args). Następnie skonstruuj obiekt za pomocą Enhancer. Jeśli twój konstruktor dla SpankingShiny nie potrzebuje argumentów, wywołanie create bez żadnych argumentów, jeśli dobrze. W przeciwnym razie podaj obiekty, które normalnie dostarczasz konstruktorowi, do metody create. Następnie używaj tylko obiektu, który otrzymałeś od create i jesteś dobry.

Jeśli chcesz uzyskać więcej informacji na temat cglib, może chcesz przeczytać na blogu: http://mydailyjava.blogspot.no/2013/11/cglib-missing-manual.html

0

miałem ten sam problem. W moim przypadku, realObj było samo proxy (Spring Bean - @Component).

Więc co miałem zrobić, to zmienić .setSuperClass() udział w:

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

zmieniłem:

e.setSuperclass(realObj.getClass()); 

Do:

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

To działało, bo jak powiedział: realObj.getClass() był sam proxy CGLIB, a ta metoda zwróciła clas generowane przez CGLIB s, na przykład a.b.c.MyClass$$EnhancerBySpringCGLIB$$1e18666c. Kiedy dodałem .getSuperClass(), zwróciłem klasę, która powróciła w pierwszej kolejności.

Powiązane problemy