3

保留中のスレッドのリストなど、いくつかの内部フィールドを備えたサービス(シングルトンフィット)が必要です(はい、すべてがスレッドセーフになるように記述されています)。問題は、@autowireこのBeanの場合、フィールドが空に見えることです。デバッグプロキシが、入力されたフィールドを持つインスタンスに正しくバインドされている(フィールド CGLIB$CALLBACK_Xは入力されたBeanに正しくリンクされている)が、提供されるフィールドは空であることがわかります。

次のコード行は、私が話していることの一般的な考え方を示しています。

@Service
public class myService{

   @Autowired
   private Monitor monitor;

   public List getSomething(){
       return monitor.getList();
   }
}


@Service
public class myStatefulService{

   //This field will be populated for sure by someone before getSomething() is called
   private List list;

   public synchronized List getSomething(){
       return this.list;
   }

   //Called by other services that self inject this bean 
   public synchronized void addToList(Object o){
      this.list.add(o);
   }
}

monitorgetList呼び出し中に変数をデバッグします

monitor => instance of correct class
 fields:
   CGLIB$BOUND => true
   CGLIB$CALLBACK_0.advised => proxyFactory (correct)
   CGLIB$CALLBACK_1.target (reference to the correct instance of myStatefulService class)
        fields:
          list => [.........] (correctly populated)
   CGLIB$CALLBACK_2 ..... 
   ......
   ......
   ......
   list => [] (the list that would be populated is empty instead)
4

3 に答える 3

15

興味がありますか、それとも実際に問題がありますか?それにもかかわらず、ここに説明があります。

CGLIBを使用してクラスをプロキシする場合、Springは。のようなサブクラスを作成しますmyService$EnhancerByCGLIB。この拡張クラスは、すべてではないにしても一部のビジネスメソッドをオーバーライドして、実際のコードに横断的関心事を適用します。

ここに本当の驚きがあります。superこの追加のサブクラスは、基本クラスのメソッドを呼び出しません。代わりに、の2番目のインスタンスを作成myServiceし、それに委任します。これは、2つのオブジェクトがあることを意味します。実際のオブジェクトとそれを指す(ラップする)CGLIB拡張オブジェクトです。

拡張クラスは単なるダミープロキシです。(継承された)基本クラスと同じフィールドがまだありますが、それらは使用されません。オブジェクトを呼び出すとaddToList()、最初にいくつかのAOPロジックが適用され、(ラップされた)の呼び出しが行われ、戻り時に残りのAOPロジックが適用されます。フィールドに触れることはありません。myService$EnhancerByCGLIBaddToList()myServicemyService$EnhancerByCGLIB.list

Springが同じクラスを使用して経由で委任できないのはなぜsuperですか?簡単にするために、最初に「生の」Beanを作成してから、後処理中にAOPプロキシを適用します。

于 2012-07-20T16:44:28.023 に答える
4

「このフィールドは、getSomething()が呼び出される前に、誰かによって確実に入力されます。」

誰かによって?いいえ、春の豆工場です。構成しない場合、何も入力されません。

すべてのBeanがSpringの管理下にある必要はありません。Listクライアントがスレッドセーフな方法でアイテムを追加および削除できるようにしたいようです。それが当てはまる場合は、@Autowiredアノテーションを削除し、新しいを作成し、List追加および削除するメソッドを公開します。

新しい並行コレクションのリストをお勧めします。

于 2012-07-20T14:08:02.977 に答える
2

CGLIBは保護されたゲッターをプロキシします。

だからあなたは持つことができます:

@Autowired
private Monitor monitor;

protected Monitor getMonitor() { return monitor; }

public List getSomething(){
    return getMonitor().getList();
}

getMonitor()は、モニターが挿入されている他のインスタンスでgetMonitor()を呼び出すようにプロキシされます。

于 2014-11-14T13:05:05.377 に答える