2013-11-03 9 views
6

Vielleicht bin ich nicht schwer genug denken oder die Antwort ist wirklich schwer fassbar. Schnelles Szenario (Probieren Sie den Code aus. Er kompiliert).CGLIB nicht in der Lage, Methoden in einer Superklasse/Superschnittstelle abzufangen

Betrachten Sie eine Legacy-Schnittstelle

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

Die ein Vermächtnis Umsetzung der kommen in I wie dieses ehrgeizige Person Jetzt

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

über Schnittstelle prüfen und eine Klasse für eine ‚neue‘ System schreibt aber das läuft innerhalb des "Legacy" -Frameworks, daher muss ich die Legacy-Basisklasse erweitern.

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

Alles funktioniert super, genau wie man erwarten würde:

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

Der obige Code Ausbeuten (wie erwartet):

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

Nun, wie Sie das ‚System sehen können. out.println() 'druckt genau die gewünschte Ausgabe. Aber ich möchte die 'System.out.println()' durch einen Logger ersetzen.

Problem:

Ich bin nicht in der Lage, die CGLIB Proxy abfangen der Methode ‚loginfo (string)‘ haben und habe es aus meiner gewünschten Nachricht durch einen Logger drucken (Ich habe die Protokollkonfiguration richtig gemacht durch die Weg). Dieser Methodenaufruf trifft "scheinbar" nicht auf den 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; 
    } 
} 

Main-Methode:

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

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

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

Die obigen Code Ausbeuten (nicht wie erwartet):

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

Wo würde ich schief gehen?

Danke!

Antwort

1

Nun, zuallererst haben Sie Glück, dass Ihr Proxy nicht getroffen wird. Wenn Sie den tatsächlichen Proxy innerhalb von intercept referenzieren würden, würden Sie mit einer Endlosschleife enden, da Ihre reflektive Methodeneinfhrung von derselben SpankingShinyProxy ausgelöst wird. Wieder und wieder.

Der Proxy funktioniert nicht, da Sie einfach den Methodenaufruf executeSomething auf Ihrem Proxy an ein nicht aufgelöstes Objekt delegieren. Sie dürfen realObj nicht verwenden. Alle Methodenaufrufe müssen von Ihrem Proxy ausgelöst werden, auch die Methodenaufrufe, die vom Proxy aufgerufen werden, müssen den Proxy selbst treffen!

Ändern Sie die letzte Zeile in Ihrer intercept-Methode zu methodProxy.invokeSuper(proxyObj, args). Konstruieren Sie dann Ihr Objekt mit der Enhancer. Wenn Ihr Konstruktor für SpankingShiny keine Argumente benötigt, rufen Sie create ohne Argumente, wenn in Ordnung. Stellen Sie andernfalls die Objekte, die Sie normalerweise dem Konstruktor liefern würden, auf die Methode create ein. Dann benutze nur das Objekt, das du von create bekommst und du bist gut.

Wenn Sie mehr Informationen über cglib möchten, können Sie diesen Blog-Artikel zu lesen: http://mydailyjava.blogspot.no/2013/11/cglib-missing-manual.html

0

Ich hatte das gleiche Problem. In meinem Fall war die realObj ein Proxy selbst (eine Spring Bean - eine @Component).

Also, was ich hatte den in .setSuperClass() Teil wurde zu tun ändern:

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

geändert I:

e.setSuperclass(realObj.getClass()); 

An:

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

Das funktionierte, weil, wie gesagt, realObj.getClass() war ein CGLIB-Proxy selbst, und diese Methode gab einen crawn-name-CGLIB-generierten clas zurück s wie a.b.c.MyClass$$EnhancerBySpringCGLIB$$1e18666c. Als ich .getSuperClass() hinzufügte, gab es die Klasse zurück, die es in erster Linie zurückgeben sollte.