@Autowired和default-autowire可以共存吗?

时间:2011-02-28 17:29:52

标签: java spring

<beans default-autowire="byType />

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

问题是当使用注释时这是如何工作的,并且根本不起作用。

我的测试显示,即使我使用

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

上下文尝试按类型自动装配字段,如果有Foo的多个实现,则会失败。因此,对于我所看到的,default-autowire不会与注释混在一起。我在文档中找不到任何具体内容。

扩展问题 - 当使用xml-only时,spring如何使用default-autowiring进行操作。即如果你有<property>。属性注入是否覆盖默认值(应该是)。

我可以做更多测试,但我更喜欢某些引文确认的行为。任何见解?

3 个答案:

答案 0 :(得分:3)

我快速尝试调试此问题,我认为这可能是春天的错误。在我看来,问题源于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);
                }
            };
        }
    };

希望有所帮助

答案 1 :(得分:1)

编辑:

  

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

你是对的。如果您不希望Spring将依赖项注入bean的某个字段,则可以使用@Qualifier注释来注入所需的依赖项。我仍然试图找到可以确认它的文档 - 我能找到的最接近的帖子是春季论坛override default-autowire setting with an annotation?

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

答案 2 :(得分:0)

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