4
votes

I have two Spring Configuration classes defined as follows

@Configuration
public class ClsA {

     @Bean
      @Qualifier("ClasA")
      public String getSomething(){
         return "somethingA";
     }
}


@Configuration
public class ClsB {

     @Bean
      @Qualifier("ClsB")
      public String getSomething(){
         return "somethingB";
     }
}

Both have the same method name. Even though qualifiers are different, the application doesn't load as it only injects one and wherever the other one is injected, if fails with noBeanDefinition exception let's say for ClsB bean qualifier.

When I keep the method name different and everything loads hunky dory.

Is this behavior normal ? Why doesn't spring load these beans just fine as they have different qualifiers ?

2

2 Answers

5
votes

The @Qualifier annotation is supposed to be used at injection points to resolve ambiguity as to which bean to inject. But in the example, you use it at bean declaration site. At declaration site, you can give a name to each bean by specifying it in @Bean annotation. So if you leave your methods with the same name, then a valid example can be as follows:

@Configuration
public class ClsA {
    @Bean("ClasA")
    public String getSomething() {
        return "somethingA";
    }
}

@Configuration
public class ClsB {
    @Bean("ClasB")
    public String getSomething() {
        return "somethingB";
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ClsB.class, ClsA.class})
public class ClsTest {
    @Autowired
    @Qualifier("ClasA") //this is the place where @Qualifier can be used
    String smthA;

    @Autowired
    @Qualifier("ClasB")
    String smthB;

    @Test
    public void test() {
        System.out.println(smthA);
        System.out.println(smthB);
    }
}

Output:

somethingA
somethingB
0
votes

1. Customize Bean Naming

Each bean name must be unique.

@Configuration
public class ClsA {

    @Bean("clasAText")
    public String getSomething() {
        return "somethingA";
    }
}
@Configuration
public class ClsB {

    @Bean("clsBText")
    public String getSomething() {
        return "somethingB";
    }
}

2. (Optional) Add qualifier metadata

@Configuration
public class ClsA {

    @Bean("clasAText")
    @Qualifier("clsA")
    public String getSomething() {
        return "somethingA";
    }
}
@Configuration
public class ClsB {

    @Bean("clsBText")
    @Qualifier("clsB")
    public String getSomething() {
        return "somethingB";
    }
}

3-1. Inject by name

@Component
public class MyComponent {

    @Resource(name = "clasAText")
    private String text;

    // ...
}

Note:

if you intend to express annotation-driven injection by name, do not primarily use @Autowired (snip). Instead, use the JSR-250 @Resource annotation

3-2. Inject by qualifier

If qualifiers have been added, these are available.

@Component
public class MyComponent {

    @Autowired
    @Qualifier("clsA")
    private String text;

    // ...
}

This answer is a fallback behavior. Name and qualifier are different one.

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