Springの“自動プロキシの対象外の原因を追跡する”
質問
Springの自動プロキシ機能をいじり始めると、文書化されているようにこの動作に遭遇することがよくあります:
を実装するクラス BeanPostProcessorインターフェースは 特別なので、彼らは扱われます コンテナによって異なります。すべて BeanPostProcessorsとその直接 参照されるBeanはインスタンス化されます 起動時に、特別の一部として の起動フェーズ ApplicationContext、次にそれらすべて BeanPostProcessorsが登録されます ソートされた方法で-に適用されます さらにすべての豆。 AOP以来 自動プロキシは次のように実装されます BeanPostProcessor自体、いいえ BeanPostProcessorsまたは直接 参照されるBeanは 自動プロキシ(したがって、 それらに「織り込まれた」側面。
このようなBeanについては、 情報ログメッセージ:“ Bean 'foo'はそうではありません すべてによって処理される資格がある BeanPostProcessors(例:not 自動プロキシの対象)”。
つまり、独自のBeanPostProcessorを作成し、そのクラスがコンテキスト内の他のBeanを直接参照する場合、参照されるBeanは自動プロキシの対象にならず、メッセージがその結果に記録されます。
私の問題は、「直接参照」が「直接参照」であるため、その直接参照がどこにあるかを追跡するのは非常に難しいことです。実際、アプリケーションコンテキストでBeanの半分を取り込む推移的な依存関係のチェーンになります。 Springが提供するのはその単一の情報メッセージだけであり、Beanがこの参照のWebでキャッチされたときを知らせる以外に、それはあまり役に立ちません。
私が開発しているBeanPostProcessorには、他のBeanへの直接参照がありますが、非常に限られた参照セットです。それにもかかわらず、ログメッセージによると、コンテキスト内のほとんどすべてのBeanが自動プロキシから除外されますが、その依存関係がどこで発生しているのかわかりません。
これを追跡するより良い方法を誰かが見つけましたか?
解決 2
この質問に何らかの閉鎖をもたらすために、初期化されていないオブジェクトグラフの崩壊は @Autowired
を使用して BeanPostProcessor
が依存関係を取得し、自動配線メカニズムによって引き起こされました。事実上、 BeanPostProcessor
が問題について発言する機会を得る前に、他のすべてのBean定義が初期化されました。解決策は、BPPに自動配線を使用しないことです。
他のヒント
このレシピに従ってください:
- IDEで
BeanPostProcessorChecker
を開きます(AbstractApplicationContext
の内部クラスです) - メソッド
postProcessAfterInitialization
の - コードを実行
-
ブレークポイントに到達したら、スタックトレースで
getBean(String、Class< T>)
の呼び出しを探します。これらの呼び出しの1つは、
BeanPostProcessor
を作成しようとします。そのBeanが原因であるはずです。
if(logger.isInfoEnabled()){
にブレークポイントを設定します
背景
この状況を想像してください:
public class FooPP implements BeanPostProcessor {
@Autowire
private Config config;
}
Springが config
を作成する必要がある場合( FooPP
の依存関係であるため)、問題があります:契約では、すべての BeanPostProcessor
作成されるすべてのBeanに適用する必要があります。ただし、Springが config
を必要とする場合、サービスの準備ができていないPP(つまり FooPP
)が少なくとも1つあります!
@Configuration
クラスを使用してこのBeanを定義すると、これはさらに悪化します。
@Configuration
public class BadSpringConfig {
@Lazy @Bean public Config config() { return new Config(); }
@Lazy @Bean public FooPP fooPP() { return new FooPP(); }
}
すべての構成クラスはBeanです。つまり、 BadSpringConfig
からBeanファクトリを構築するには、Springはポストプロセッサ fooPP
を適用する必要がありますが、そのためには、まずBeanファクトリが必要です...
この例では、循環依存関係の1つを解除することができます。 FooPP
に BeanFactoryAware
を実装させ、Springに BeanFactory
をポストプロセッサに注入させることができます。そうすれば、自動配線は必要ありません。
コードの後で、遅延してBeanを要求できます。
private LazyInit<Config> helper = new LazyInit<Config>() {
@Override
protected InjectionHelper computeValue() {
return beanFactory.getBean( Config.class );
}
};
@Override
public Object postProcessBeforeInitialization( Object bean, String beanName ) throws BeansException {
String value = helper.get().getConfig(...);
}
( LazyInitのソース)
Beanファクトリとポストプロセッサ間のサイクルを中断するには、XML構成ファイルでポストプロセッサを構成する必要があります。 Springはそれを読み取り、混乱することなくすべての構造を構築できます。
助けになるかどうかはわかりませんが、Eclipse Spring IDE グラフビューは、Bean参照の整理に役立つようです。