2012-07-16 6 views
6

@Transactional注釈でマークされたDAOメソッドが実行されるたびに、TransactionInterceptorを使用して、データベースの一部の情報をThreadLocalに設定しています。照会を異なるデータベース・パーティションに経路指定できるようにするためには、これが必要です。Spring Bean自体がAOPプロキシでラップされているかどうかを検出するにはどうすればよいですか?

これは、ほとんどのDAOのメソッドのために正常に動作します:

// this causes the invoke method to set a thread-local with the host name of 
// the database server the partition is on 
@Transactional 
public int deleteAll() throws LocalDataException { 

我々はDAOの内部DAO 代理オブジェクト自体を参照する必要があるときに問題があります。通常、私たちは、呼び出し側がプロキシDAOを渡す持っている必要があります:

public Pager<Foo, Long> getPager(FooDao proxyDao) { 

これは明らかに総あるコードに次のようになります。

fooDao.getPager(fooDao); 

問題は、私たちがFooDaoの内側にあるとき、thisは我々が必要ないプロキシDAOであるということです。

Beanの周囲にプロキシラッパーがあることを発見するためのより良いメカニズムがありますか?私はSpring AOPUtilsを見ましたが、オブジェクトのプロキシを見つける方法がありません。私は例えばisAopProxy(...)を望ましくない。私もSpring AOP docsを読んだことがありますが、私が避けたいと思っていた自分のAOPネイティブコードを実装していない限り、そこには解決策が見えません。

私は、ApplicationContextAwareユーティリティー・ビーンとsetProxyDao(...)メソッドを使ってDAOを自分自身に注入できると思うが、それはハックのようだ。他のアイデアはどのように私は、Bean自体の中からそれを利用できるようにプロキシを検出することができますか?助けてくれてありがとう。

+0

オプションを持たないネイティブのAspectjロード/コンパイル時間を使用しています - アドバイスはプロキシーに織り込まれているので、プロキシとこの参照がプロキシ内で発行されるべきではありませんか? –

+0

'this'は@Thorbjørnを行いません。なぜなら、ポストステートとして、私はプロキシ_not_ bean自体を必要とするからです。 – Gray

+0

私自身のネイティブAOPを書くことは、私の唯一の解決策@Bijuかもしれません。できればそれを避けることを望んでいた。ありがとうtho。 – Gray

答えて

4

あなたはAspectJのは、時間や負荷時の織りがあなたのために動作しませんコンパイルすることを考慮すると、示唆されているものの線に沿ってハックソリューション:

これらの線に沿ってインターフェイスを作成します。

public interface ProxyAware<T> { 
    void setProxy(T proxy); 
} 

レッツ

public class ProxyInjectingBeanPostProcessor implements BeanPostProcessor, Ordered { 
    @Override 
    public Object postProcessBeforeInitialization(Object bean, String beanName) { 
     return bean; 
    } 

    @Override 
    public Object postProcessAfterInitialization(Object bean, String beanName) { 
     if (AopUtils.isAopProxy((bean))){ 
      try { 
       Object target = ((Advised)bean).getTargetSource().getTarget(); 
       if (target instanceof ProxyAware){ 
        ((ProxyAware) target).setProxy(bean); 
       } 
      } catch (Exception e) { 
       // ignore 
      } 
     } 
     return bean; 
    } 

    @Override 
    public int getOrder() { 
     return Ordered.LOWEST_PRECEDENCE; 
    } 
} 

それを:あなたのダオの今、これらの線に沿って、最後の実行を命じインターフェースでBeanPostProcessorを作成し、ProxyAwareの実装を実装醜いですが、動作します。

+0

Ooooh。おいしい。私はそれの外観が好きです@ Biju。私はそれを試してみましょう... – Gray

+0

何らかの理由で私のAOPに悪影響を及ぼしているように思えたので、私は 'Ordered'を削除しました。しかし、そうでなければ働いている。おそらくあなたは 'Ordered'を削除するべきでしょうか?再度、感謝します。 – Gray

2

Springから提供される便利な静的ユーティリティAopContext.currentProxy()があります。このメソッドは、呼び出し元のオブジェクトにプロキシを返します。

これは悪い習慣と考えられますが、意味的には同じ方法がJava EEにも存在します:SessionContext.getBusinessObject()

このユーティリティ方法とさまざまな落とし穴に関する記事はほとんど書かれていません:123です。

+0

私は、現在のプロキシが存在しないように私が電話をかけるときに私がプロキシではないと言っ始めました。しかし、 'getPager()'メソッドを '@ Transactional'とマークすることができなかった理由はありません。これは役に立つ@トーマスです。ありがとう! – Gray

2

他のBeanリファレンスの場合と同じように、BeanをBeanに挿入するには、Springを使用します。特別な処置は必要ありません。

このような変数の存在は、クラスが何らかの形でプロキシされることを明示的にクラス設計で認めます。これは必ずしも悪いことではありません.Aopはクラス契約を破る動作を変更する可能性があるためです。

通常、Beanリファレンスはインターフェイス用であり、そのインターフェイスは自己参照内部メソッド用のインターフェイスでもあります。

簡単にしてください。そういうわけで、狂気がある。 :-)

さらに重要なことに、意味が意味を成すことを確認してください。これを行う必要があるのは、クラスが複数の責任の中で混ざり合っていることを別の豆に分解したような臭いかもしれません。

+0

ありがとうございました。私はすべての私のDAOにその注射をする必要がないことを望んでいました。 'BeanPostProcessor'は動作しているようですが、これを念頭に置いておきます。 – Gray