【问题标题】:Can @Autowired and default-autowire coexist?@Autowired 和 default-autowire 可以共存吗?
【发布时间】:2011-02-28 17:29:51
【问题描述】:
<beans default-autowire="byType />

表示如果所需类型的 bean 不超过 1 个,bean 的所有字段将自动注入依赖项。

问题是,当使用注解时,它是如何工作的,并且它是否有效。

我的测试表明,即使我使用

@Resource(name="someConcreteFoo")
private Foo foo;

上下文尝试按类型自动装配字段,如果Foo 有多个实现,则会失败。所以,就我所见,default-autowire 没有与注释混合。我在文档中找不到任何具体内容。

扩展问题 - 当使用 xml-only 时,spring 如何处理默认自动装配。 IE。如果你有&lt;property&gt;。属性注入是否覆盖默认值(应该是)。

我可以做更多的测试,但我更希望通过一些引用来确认行为。有什么见解吗?

【问题讨论】:

  • 一个特别没用的说明:类似情况我看源码;它比撰写和发布答案花费的时间更少,并且让我确定我确切地知道为什么/如何。不幸的是,我不使用弹簧,所以没有直接的答案。
  • @bestsss 我也这样做。尽管我对 spring 的代码相当熟悉(在各种情况下都这样做过),但自动装配机制还是有点困难。如果我对此有疑问,也许我会花几个小时研究。目前出于好奇,所以我只是在检查是否有人已经意识到这一点。
  • 有点难;我的猜测(没有任何经验)断点设置器,你确定你不会自己调用,检查堆栈跟踪。直到代码(或缺少)绑定命名资源。并为自己做这件事而感到自豪。我几乎完全从源代码编译第 3 方库(开源库)。
  • 不编译它们,但我有源代码 ;)

标签: java spring


【解决方案1】:

我很快就调试了这个问题,我认为这很可能是春季的一个错误。在我看来,问题源于AbstractAutowireCapableBeanFactory中的以下代码

/**
 * Populate the bean instance in the given BeanWrapper with the property values
 * from the bean definition.
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param bw BeanWrapper with bean instance
 */
protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {
    PropertyValues pvs = mbd.getPropertyValues();

    if (bw == null) {
        if (!pvs.isEmpty()) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
        else {
            // Skip property population phase for null instance.
            return;
        }
    }

    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    boolean continueWithPropertyPopulation = true;

    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
    }

    if (!continueWithPropertyPopulation) {
        return;
    }

    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

        // Add property values based on autowire by name if applicable.
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }

        // Add property values based on autowire by type if applicable.
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }

        pvs = newPvs;
    }

    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

    if (hasInstAwareBpps || needsDepCheck) {
        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);
        if (hasInstAwareBpps) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    if (pvs == null) {
                        return;
                    }
                }
            }
        }
        if (needsDepCheck) {
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }
    }

    applyPropertyValues(beanName, mbd, bw, pvs);
}

我个人认为应用自动装配和 InstantiationAwareBeanPostProcessor 的顺序是错误的,因为 @Resource 注释只会应用在 postProcessPropertyValues 中,所以在自动装配之后(此时自动装配已经失败)。

现在我不知道更改调用顺序是否会产生影响,以便在自动装配之前解决 @Resource 注释,但这很可能是作为错误/修复提出的问题(我使用了以下方式加载我的测试应用程序上下文来解决这个问题):

    ApplicationContext ctx = new ClassPathXmlApplicationContext("test/appctx.xml") {
        protected org.springframework.beans.factory.support.DefaultListableBeanFactory createBeanFactory() {
            return new DefaultListableBeanFactory(getInternalParentBeanFactory()) {
                protected void populateBean(String beanName, org.springframework.beans.factory.support.AbstractBeanDefinition mbd, org.springframework.beans.BeanWrapper bw) {
                    PropertyValues pvs = mbd.getPropertyValues();

                    if (bw == null) {
                        if (!pvs.isEmpty()) {
                            throw new BeanCreationException(
                                    mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
                        }
                        else {
                            // Skip property population phase for null instance.
                            return;
                        }
                    }

                    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
                    // state of the bean before properties are set. This can be used, for example,
                    // to support styles of field injection.
                    boolean continueWithPropertyPopulation = true;

                    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                        for (BeanPostProcessor bp : getBeanPostProcessors()) {
                            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                                    continueWithPropertyPopulation = false;
                                    break;
                                }
                            }
                        }
                    }

                    if (!continueWithPropertyPopulation) {
                        return;
                    }

                    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
                    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

                    if (hasInstAwareBpps || needsDepCheck) {
                        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);
                        if (hasInstAwareBpps) {
                            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                                    pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                                    if (pvs == null) {
                                        return;
                                    }
                                }
                            }
                        }
                        if (needsDepCheck) {
                            checkDependencies(beanName, mbd, filteredPds, pvs);
                        }
                    }

                    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

                        // Add property values based on autowire by name if applicable.
                        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
                            autowireByName(beanName, mbd, bw, newPvs);
                        }

                        // Add property values based on autowire by type if applicable.
                        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                            autowireByType(beanName, mbd, bw, newPvs);
                        }

                        pvs = newPvs;
                    }

                    applyPropertyValues(beanName, mbd, bw, pvs);
                }
            };
        }
    };

希望有帮助

【讨论】:

    【解决方案2】:

    编辑:

    属性注入是否覆盖默认值(应该是)。

    你是对的。如果您不希望 Spring 将依赖项注入到 bean 的某个字段,则可以使用 @Qualifier 注释来注入所需的依赖项。我仍在努力寻找可以证实这一点的文档——我能找到的最接近的是春季论坛上的帖子override default-autowire setting with an annotation?

    编辑:这是另一篇帖子@Resource considered only after default-autowire="byName",它描述了使用新的InstantiationAwareBeanPostProcessor 更改连线顺序以使setter 上的@Resource 优先于default-autowire。

    【讨论】:

      【解决方案3】:

      据我所知,default-autowire 属性只为那些连接在 XML 配置中的 bean 定义了默认的“自动装配模式”!然后基于注释的自动装配与此无关。 @Autowired 按类型始终@Resource 按名称始终
      请参阅 Spring 参考文档 3.9.3 中的提示:
      “如果您打算通过名称来表示注解驱动的注入,请不要主要使用 @Autowired,即使在技术上能够通过 @ 引用 bean 名称限定符值。取而代之的是使用 JSR-250 @Resource 注释,它在语义上定义为通过其唯一名称标识特定目标组件,声明的类型与匹配过程无关。"

      【讨论】:

      • 是的,但如果你同时使用,它就不起作用。这并不是说我希望 default-autowire 对注释起作用,而是它忽略了注释并失败了。
      • 您的意思是您使用@Resource(name="someConcreteFoo") private Foo foo;default-autowire="byType"default-autowire="byName" 收到异常,但不会发生异常?我认为这将是 Spring 中的一个错误。
      • 使用任何默认自动连线,而不仅仅是按类型。关键是 - 如果要使用注释,则不能使用 default-autowire。我想确保是这种情况
      • 当然可以,默认自动装配模式适用于 XML 配置中的装配(我更喜欢按名称),基于注释的自动装配是另一个独立的故事。如果您使用@Resource(name="someConcreteFoo") 收到异常,则这完全独立于您的原始问题。也许你应该发布那个例外。
      • @Resource(name="..") 本身有效。如果默认自动装配是打开的,它不会
      猜你喜欢
      • 2018-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-22
      • 2011-01-21
      • 2017-01-28
      相关资源
      最近更新 更多