Java 追踪 Spring 的“不符合自动代理条件”的原因

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1201726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:51:35  来源:igfitidea点击:

Tracking down cause of Spring's "not eligible for auto-proxying"

javaspringaop

提问by skaffman

When you start messing around with Spring's auto-proxy stuff, you often run into this behaviour as documented:

当您开始使用 Spring 的自动代理时,您经常会遇到记录中的这种行为:

Classes that implement the BeanPostProcessor interface are special, and so they are treated differently by the container. All BeanPostProcessors and their directly referenced beans will be instantiated on startup, as part of the special startup phase of the ApplicationContext, then all those BeanPostProcessors will be registered in a sorted fashion - and applied to all further beans. Since AOP auto-proxying is implemented as a BeanPostProcessor itself, no BeanPostProcessors or directly referenced beans are eligible for auto-proxying (and thus will not have aspects 'woven' into them.

For any such bean, you should see an info log message: “Bean 'foo' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)”.

实现 BeanPostProcessor 接口的类是特殊的,因此容器对它们进行不同的处理。所有 BeanPostProcessor 及其直接引用的 bean 将在启动时实例化,作为 ApplicationContext 的特殊启动阶段的一部分,然后所有这些 BeanPostProcessor 将以排序的方式注册 - 并应用于所有其他 bean。由于 AOP 自动代理是作为 BeanPostProcessor 本身实现的,因此没有 BeanPostProcessor 或直接引用的 bean 有资格进行自动代理(因此不会将方面“编织”到它们中。

对于任何此类 bean,您应该看到一条信息日志消息:“Bean 'foo' 不符合所有 BeanPostProcessor 的处理条件(例如:不符合自动代理的条件)”。

In other words, if I write my own BeanPostProcessor, and that class directly references other beans in the context, then those referenced beans will not be eligible for auto-proxying, and a message is logged to that effect.

换句话说,如果我编写自己的 BeanPostProcessor,并且该类直接引用上下文中的其他 bean,那么这些引用的 bean 将没有资格进行自动代理,并且会记录一条消息以实现该效果。

My problem is that tracking down where that direct reference is can be very difficult, since the "direct reference" can in fact be a chain of transitive dependencies that ends up taking in half the beans in the application context. All Spring gives you is that single info message, and it's not really much help, beyond telling you when a bean has been caught in this web of references.

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

The BeanPostProcessor I'm developing does have direct references to other beans, but it's a very limited set of references. Despite this, pretty much every bean in my context is then being excluded from being auto-proxied, according to the log messages, but I can't see where that dependency is happening.

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

Has anyone found a better way of tracking this down?

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

采纳答案by skaffman

Just to bring some closure to this question, the collapse of the uninitialized object graph was caused by the BeanPostProcessorusing @Autowiredto get its dependencies, and the autowire mechanism effectively caused every other bean definition to be initialized before my BeanPostProcessorgot a chance to have a say in the matter. The solution is not to use autowiring for your BPPs.

只是为了结束这个问题,未初始化的对象图的崩溃是由BeanPostProcessorusing@Autowired获取其依赖项引起的,并且自动装配机制有效地导致所有其他 bean 定义在我BeanPostProcessor有机会发表意见之前被初始化事情。解决方案不是为您的 BPP 使用自动装配。

回答by Tim

Not sure if it's of any help, but the Eclipse Spring IDE's graph viewlooks like it could be helpful in sorting out bean references..

不确定它是否有任何帮助,但 Eclipse Spring IDE图形视图看起来可能有助于整理 bean 引用。

回答by Aaron Digulla

Follow this recipe:

按照这个食谱:

  1. Open BeanPostProcessorCheckerin your IDE (it's an inner class of AbstractApplicationContext)
  2. Set a breakpoint on if (logger.isInfoEnabled()) {in the method postProcessAfterInitialization
  3. Run your code
  4. When you hit the breakpoint, look for calls to getBean(String,Class<T>)in your stack trace.

    One of these calls will try to create a BeanPostProcessor. That bean should be the culprit.

  1. BeanPostProcessorChecker在您的 IDE 中打开(它是 的内部类AbstractApplicationContext
  2. if (logger.isInfoEnabled()) {在方法中设置断点postProcessAfterInitialization
  3. 运行你的代码
  4. 当您遇到断点时,请getBean(String,Class<T>)在堆栈跟踪中查找对 的调用。

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

Background

背景

Imagine this situation:

想象一下这种情况:

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

When Spring has to create config(since it's a dependency of FooPP), it has a problem: The contract says that all BeanPostProcessormust be applied to every bean that is being created. But when Spring needs config, there is at least one PP (namely FooPP) which isn't ready for service!

当 Spring 必须创建时config(因为它是 的依赖项FooPP),它有一个问题:契约说 allBeanPostProcessor必须应用于正在创建的每个 bean。但是当 Spring 需要 时config,至少有一个 PP(即FooPP)没有准备好服务!

This gets worse when you use an @Configurationclass to define this bean:

当你使用一个@Configuration类来定义这个 bean时,情况会变得更糟:

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

Every configuration class is a bean. That means to build a bean factory from BadSpringConfig, Spring needs to apply the post-processor fooPPbut in order to do that, it first needs the bean factory ...

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

In this example, it's possible to break one of the cyclic dependencies. You can make FooPPimplement BeanFactoryAwareto get Spring inject the BeanFactoryinto the post processor. That way, you don't need autowiring.

在这个例子中,可以打破循环依赖之一。您可以FooPP实现BeanFactoryAware让 Spring 注入BeanFactory后处理器。这样,您就不需要自动装配。

Later in the code, you can lazily ask for the bean:

在代码的后面,你可以懒惰地请求 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)

LazyInit 的来源

To break the cycle between the bean factory and the post processor, you need to configure the post processor in an XML config file. Spring can read that and build all the structures without getting confused.

要打破 bean 工厂和后处理器之间的循环,您需要在 XML 配置文件中配置后处理器。Spring 可以读取并构建所有结构而不会感到困惑。