Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autowired is not throwing exceptions for multiple beans of same type

Tags:

java

spring

I am working on basic @Autowired program where I have 2 classes Alpha and Beta. Here Alpha has a dependency on Beta using @Autowired.

In spring configuration file I am created more than 1 bean for class Beta type, so I was expecting an exception from Spring when it tries to inject the dependency in Alpha class as there are 2 Beta beans instead of 1. But in my program I am not getting any exceptions, it is working perfectly fine.

Here is my code:

Alpha.java

public class Alpha {
    @Autowired
    private Beta beta;

    public Alpha() {
        System.out.println("Inside Alpha constructor.");
    }

    @Override
    public String toString() {
        return "Alpha [beta=" + beta + "]";
    }

}

Beta.java

public class Beta {
    public Beta() {
        System.out.println("Inside Beta constructor.");
    }

    @Override
    public String toString() {
        return "This is Beta";
    }
}

spring-config.xml

<beans>

   <context:annotation-config/>

   <bean id="alpha" class="Alpha">
   </bean>

   <bean id="beta" class="Beta">
   </bean>

   <bean id="beta1" class="Beta">
   </bean>

   <bean id="beta2" class="Beta">
   </bean>

</beans>

Main program:

public static void main(String[] args) {
      ApplicationContext context = 
             new ClassPathXmlApplicationContext("beans.xml");

      Alpha alpha = (Alpha) context.getBean("alpha");

      System.out.println(alpha);
   }

This is the output:

Inside Alpha constructor.
Inside Beta constructor.
Inside Beta constructor.
Inside Beta constructor.
Alpha [beta=This is Beta]
like image 865
learner Avatar asked Feb 10 '23 08:02

learner


1 Answers

It autowires by name. You have three beans of type Beta1, named beta, beta1, and beta2. Your field is named beta. Spring will use that as a hint to find the corresponding bean.

If you named your field

@Autowired
private Beta whatever;

there would be no (useful) hint to Spring, and it would be unable to choose an appropriate bean.

It's not exactly obvious in the Spring documentation, you have to infer it from various chapters.

From the notes in the chapter concerning @Autowired

If you intend to express annotation-driven injection by name, do not primarily use @Autowired, even if is technically capable of referring to a bean name through @Qualifier values. Instead, use the JSR-250 @Resource annotation, which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process.

For @Qualifier values (or rather the lack of @Qualifier)

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

Then from the chapter on @Resource

If no name is specified [in the @Resource annotation] explicitly, the default name is derived from the field name or setter method. In case of a field, it takes the field name; in case of a setter method, it takes the bean property name.

like image 103
Sotirios Delimanolis Avatar answered Feb 13 '23 02:02

Sotirios Delimanolis