Springの自動プロキシ機能をいじり始めると、文書化されているようにこの動作に遭遇することがよくあります。
BeanPostProcessorインターフェースを実装するクラスは特別であるため、コンテナによって異なる方法で処理されます。すべてのBeanPostProcessorとそれらの直接参照されるBeanは、ApplicationContextの特別な起動フェーズの一部として起動時にインスタンス化され、それらすべてのBeanPostProcessorsはソートされた方法で登録され、すべてのBeanに適用されます。 AOP自動プロキシはBeanPostProcessor自体として実装されているため、BeanPostProcessorまたは直接参照されるBeanは自動プロキシに適格ではありません(したがって、「織り込まれた」側面はありません)。
このようなBeanについては、「Bean 'foo'はすべてのBeanPostProcessorsによって処理される資格がありません(たとえば、自動プロキシの資格がありません)」という情報ログメッセージが表示されます。
つまり、独自のBeanPostProcessorを記述し、そのクラスがコンテキスト内の他のBeanを直接参照する場合、それらの参照されるBeanは自動プロキシの対象にならず、その結果メッセージがログに記録されます。
私の問題は、「直接参照」が実際にはアプリケーションコンテキストのBeanの半分を取り込む推移的な依存関係のチェーンになる可能性があるため、その直接参照がどこにあるかを追跡することが非常に難しいことです。 Springが提供するのは、その単一の情報メッセージだけであり、この参照のWebでBeanがキャッチされたことを伝える以外に、それはあまり役に立ちません。
私が開発しているBeanPostProcessorには、他のBeanへの直接参照がありますが、非常に限られた参照セットです。それにもかかわらず、ログメッセージによると、コンテキスト内のほとんどすべてのBeanが自動プロキシから除外されていますが、その依存関係がどこで発生しているのかわかりません。
誰かがこれを追跡するより良い方法を見つけましたか?
この質問に何らかの閉鎖をもたらすために、初期化されていないオブジェクトグラフの崩壊は、依存関係を取得するために@Autowired
を使用するBeanPostProcessor
によって引き起こされ、autowireメカニズムにより他のすべてのBean定義が初期化されましたBeanPostProcessor
が問題について発言する機会を得る前に。解決策は、BPPに自動配線を使用しないことです。
このレシピに従ってください:
BeanPostProcessorChecker
の内部クラスです)でAbstractApplicationContext
を開きますpostProcessAfterInitialization
のif (logger.isInfoEnabled()) {
にブレークポイントを設定しますブレークポイントに到達したら、スタックトレースでgetBean(String,Class<T>)
の呼び出しを探します。
これらの呼び出しの1つは、BeanPostProcessor
を作成しようとします。その豆が犯人であるべきです。
背景
この状況を想像してください:
public class FooPP implements BeanPostProcessor {
@Autowire
private Config config;
}
(config
の依存関係であるため)SpringがFooPP
を作成する必要がある場合、問題があります。契約では、作成されるすべてのBeanにすべてのBeanPostProcessor
を適用する必要があるとされています。しかし、Springがconfig
を必要とする場合、少なくとも1つのPP(つまりFooPP
)があり、サービスの準備ができていません!
@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 の graph view は、Bean参照の整理に役立つようです。