代码之家  ›  专栏  ›  技术社区  ›  skaffman

追查弹簧“不具备自动代理资格”的原因

  •  38
  • skaffman  · 技术社区  · 15 年前

    当你开始摆弄Spring的自动代理程序时,你经常会遇到这样的行为,如文档所示:

    实现的类 BeanPostProcessor接口是 特别的,所以他们被对待 不同的容器。所有 bean后处理器及其直接 引用的bean将被实例化 启动时,作为 的启动阶段 应用程序上下文,然后所有这些 BeanPostProcessors将被注册 以排序的方式-并应用于 所有的豆子。自AOP以来 自动代理实现为 BeanPostProcessor本身,否 BeanPostProcessors或直接 引用的bean符合 自动代理(因此不会 各方面“交织”在一起。

    对于任何这样的豆子,您应该看到 信息日志消息:bean'foo'不是 有资格获得所有人的处理 beanPostProcessors(例如:not 具备自动代理资格)__。

    换句话说,如果我编写自己的beanPostProcessor,并且该类直接引用上下文中的其他bean,那么这些引用的bean将不符合自动代理的条件,并且会为此记录一条消息。

    我的问题是,跟踪直接引用的位置可能非常困难,因为“直接引用”实际上可以是一个传递依赖链,最终在应用程序上下文中占据一半的bean。所有Spring提供给您的都是单一的信息消息,除了告诉您bean何时被捕获在这个引用网络中之外,它并没有什么帮助。

    我正在开发的beanPostProcessor确实直接引用了其他bean,但它的引用集非常有限。尽管如此,根据日志消息,我的上下文中的几乎所有bean都被排除在自动代理之外,但是我看不到这种依赖发生在哪里。

    有人找到更好的方法来追踪这个吗?

    3 回复  |  直到 6 年前
        1
  •  25
  •   Aaron Digulla    10 年前

    按照这个食谱:

    1. 正常开放 BeanPostProcessorChecker 在您的IDE中(它是 AbstractApplicationContext )
    2. 在上设置断点 if (logger.isInfoEnabled()) { 在该方法中 postProcessAfterInitialization
    3. 运行代码
    4. 当您到达断点时,查找对 getBean(String,Class<T>) 在堆栈跟踪中。

      其中一个调用将尝试创建 BeanPostProcessor . 那颗豆子应该是罪魁祸首。

    背景

    想象一下这种情况:

    public class FooPP implements BeanPostProcessor {
        @Autowire
        private Config config;
    }
    

    当春天必须创造 config (因为它依赖于 FooPP )有个问题:合同上说 后处理器 必须应用于正在创建的每个bean。但当春天需要的时候 配置 ,至少有一个PP(即 福普 )服务还没准备好!

    当你使用 @Configuration 定义此bean的类:

    @Configuration
    public class BadSpringConfig {
         @Lazy @Bean public Config config() { return new Config(); }
         @Lazy @Bean public FooPP fooPP() { return new FooPP(); }
    }
    

    每个配置类都是bean。这意味着要从 BadSpringConfig ,Spring需要应用后处理器 fooPP 但要做到这一点,首先需要豆工厂…

    在这个例子中,可以打破一个循环依赖关系。你可以做 福普 实施 BeanFactoryAware 为了得到弹簧注入 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(...);
    }
    

    ( source for LazyInit )

    要打破bean工厂和后处理器之间的循环,需要在XML配置文件中配置后处理器。Spring可以读取这些信息,并且构建所有的结构而不被混淆。

        2
  •  19
  •   zwessels Rémi Doolaeghe    6 年前

    为了解决这个问题,未初始化对象图的崩溃是由 BeanPostProcessor 使用 @Autowired 为了获得它的依赖性,autowire机制有效地导致了其他所有bean定义在 后处理器 在这件事上有发言权。解决方案是不要为BPP使用自动布线。

        3
  •  4
  •   Tim    15 年前

    不确定是否有帮助,但是日食 Spring IDE graph view 看起来它可能有助于排序bean引用。