Search code examples
javaspringannotationsspring-annotations

@Autowired finding ambiguous dependencies and still works. How?


Why is Spring not throwing NoSuchBeanDefinitionException where there are ambiguous dependencies and more than one bean candidates found for autowiring using @Autowired annotation ?

I have this simple beans.xml that has two same beans with different ids category and category1 and for some reason Spring picks the category bean for autowiring. I was under the impression that @Autowired annotation uses byType autowiring internally and since here there are more than one matches found here Spring will throw NoSuchBeanDefinitionException exception.

I am using spring version 3.2.13.RELEASE here.

beans.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans 
     .....   ">

        <context:annotation-config />

        <bean id="product" class="com.study.spring.Product">
            <property name="id" value="101"/>
            <property name="name" value="Apple iPhone"/>
            <property name="active" value="true"/>
        </bean>

        <bean id="category1" class="com.study.spring.Category">
            <property name="id" value="202"/>
            <property name="name" value="Phone"/>
            <property name="active" value="true"/>
        </bean>

        <bean id="category" class="com.study.spring.Category">
            <property name="id" value="201"/>
            <property name="name" value="Communications"/>
            <property name="active" value="true"/>
        </bean>

    </beans>

Product.java

package com.study.spring;

import org.springframework.beans.factory.annotation.Autowired;

public class Product {
    private int id;
    private String name;
    private boolean active;
    @Autowired
    private Category category;

    //getters and setters here
}

Solution

  • It takes the Category object with the id category because it matches the name of the field. The old spring documentation explain this as:

    "For a fallback match, the bean name is considered as a default qualifier value."

    The current documentation explains this a bit clearer. You have a "byName" autowiring situation here:

    Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name, and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master, and uses it to set the property.