2013-11-03 9 views
6

私は十分に難しいと思っていないかもしれませんし、答えが本当に分かりにくいかもしれません。クイックシナリオ(コードを試してみるとコンパイルされます)。CGLIBがスーパークラス/スーパーインターフェースのメソッドをインターセプトできない

今、私はこの野心的な人として来て、「新規」システムのためのクラスを書き込み

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

上のインターフェイスのレガシー実装を検討し、レガシーインタフェース

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

を考えるが、それは 'レガシー'フレームワークの中で動くので、私はレガシーベースクラスを拡張する必要があります。

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

すべては、あなたが期待するだけのように、素晴らしい作品:

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

上記のコード利回り(予想通り):

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

今、あなたが見ることができるよう、「システム。 out.println() 'は、忠実に出力を出力します。しかし、私は 'System.out.println()'をロガーに置き換えたいと思います。

は問題:私は「LOGINFO(文字列)」へのメソッドインターセプトCGLIBプロキシを持つことができないことだし、それはロガーを通じて私の希望のメッセージをプリントアウトしてい

(私は右のロギングコンフィギュレーションを行っています方法)。そのメソッド呼び出しは、明らかにプロキシにヒットしません。

コード:

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

主な方法:

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

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

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

上記のコード利回り(期待できないように):

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

私は間違って行くことでしょうか?

ありがとうございます!

答えて

1

まず、プロキシがヒットしなかったのは幸いです。 intercept内の実際のプロキシを参照していた場合は、反射メソッドの呼び出しが同じSpankingShinyProxyによって送出されるため、無限ループになります。何回も何回も。

プロキシのメソッド呼び出しexecuteSomethingを非プロキシオブジェクトに委任しただけなので、プロキシは機能しません。 realObjは使用しないでください。すべてのメソッド呼び出しは、プロキシによってディスパッチされる必要があります。

interceptメソッドの最後の行をmethodProxy.invokeSuper(proxyObj, args)に変更してください。次に、Enhancerを使用してオブジェクトを作成します。 SpankingShinyのコンストラクタに引数が必要ない場合は、createを引数なしで呼び出すと問題ありません。それ以外の場合は、コンストラクタに通常提供するオブジェクトをcreateメソッドに渡します。その後、取得するオブジェクトはcreateからのみ使用してください。

あなたはCGLIBの詳細情報が必要な場合、あなたはこのブログ記事を参照することもできます。http://mydailyjava.blogspot.no/2013/11/cglib-missing-manual.html

0

私は同じ問題を抱えていました。私の場合、realObjはプロキシそのものでした(Spring Bean-a @Component)。

それでは、私がしなければならなかったことに.setSuperClass()一部を変更した:私は変更

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

e.setSuperclass(realObj.getClass()); 

た:

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

言ったようにこれは、ために働きましたrealObj.getClass()はCGLIBプロキシ自体であり、そのメソッドはCrazy-Name-CGLIB生成クラスを返しましたs、例えばa.b.c.MyClass$$EnhancerBySpringCGLIB$$1e18666c。私が.getSuperClass()を追加すると、最初に戻ってきたはずのクラスが返されました。

関連する問題