追查Spring的“不符合自动代理条件”的原因
当你开始搞乱Spring的自动代理的东西,你经常遇到这样的行为logging:
实现BeanPostProcessor接口的类是特殊的,所以它们被容器区别对待。 所有BeanPostProcessors及其直接引用的Bean将在启动时实例化,作为ApplicationContext的特殊启动阶段的一部分,然后所有BeanPostProcessors将以已sorting的方式注册 – 并应用于所有其他bean。 由于AOP自动代理被实现为一个BeanPostProcessor本身,所以没有BeanPostProcessors或直接引用的Bean有资格进行自动代理(因此不会有“编织”的方面)。
对于任何这样的bean,您应该看到一条信息日志消息:“Bean'foo'不适合所有BeanPostProcessors处理(例如:不适合自动代理)”。
换句话说,如果我编写自己的BeanPostProcessor,并且该类直接引用上下文中的其他Bean,那么这些引用的Bean将不具备自动代理的资格,并且会为此logging一条消息。
我的问题是跟踪直接引用的位置可能非常困难,因为“直接引用”实际上可能是一个传递依赖链,最终在应用程序上下文中占用一半的bean。 所有的spring给你的是单一的信息消息,并没有什么帮助,除了告诉你什么时候一个bean被引用到这个网页中。
我正在开发的BeanPostProcessor确实具有对其他bean的直接引用,但它是一组非常有限的引用。 尽pipe如此,根据日志消息,几乎我的上下文中的每个bean都被排除在自动代理之外,但是我无法看到依赖关系在哪里发生。
有没有人find一个更好的方法来跟踪这个呢?
遵循这个秘诀:
- 在您的IDE中打开
BeanPostProcessorChecker
(这是AbstractApplicationContext
的内部类) - 在方法
postProcessAfterInitialization
设置一个断点if (logger.isInfoEnabled()) {
- 运行你的代码
-
当你打断点时,在堆栈跟踪中查找对
getBean(String,Class<T>)
的调用。其中一个调用将尝试创build一个
BeanPostProcessor
。 那个豆子应该是罪魁祸首。
背景
想象一下这种情况:
public class FooPP implements BeanPostProcessor { @Autowire private Config config; }
当Spring必须创buildconfig
(因为它是FooPP
的依赖)时,它有一个问题:合约说所有的BeanPostProcessor
必须被应用到每个正在被创build的bean上。 但是当Spring需要config
,至less有一个PP(即FooPP
)没有准备好服务!
当你使用@Configuration
类来定义这个bean时,情况会变得更糟:
@Configuration public class BadSpringConfig { @Lazy @Bean public Config config() { return new Config(); } @Lazy @Bean public FooPP fooPP() { return new FooPP(); } }
每个configuration类都是一个bean。 这意味着从BadSpringConfig
构build一个bean工厂,Spring需要应用后处理器fooPP
但为了这样做,它首先需要bean工厂…
在这个例子中,可能会破坏一个循环的依赖关系。 你可以让FooPP
实现BeanFactoryAware
来让Spring将BeanFactory
注入到后处理器中。 这样,你不需要自动assembly。
在代码后面,你可以懒洋洋地问这个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 )
要打破豆工厂和后处理器之间的循环,需要在XMLconfiguration文件中configuration后处理器。 Spring可以读取并构build所有的结构而不会感到困惑。
为了解决这个问题,未初始化的对象图的崩溃是由使用@Autowired
的BeanPostProcessor
来获得它的依赖关系引起的,自动assembly机制有效地导致了每个其他的bean定义在我的BeanPostProcessor
得到机会之前被初始化在这个问题上的一个说法。 解决scheme – 不要使用自动assembly为您的BPP …
不确定是否有任何帮助,但Eclipse Spring IDE的graphics视图看起来像可能有助于对bean引用进行sorting。