4
votes

I just found a behaviour of Spring that I cannot understand. I am using Spring Boot 1.5.x.

In a configuration class, I declared two different beans.

@Configuration
class Config {
    @Bean("regularRestTemplate")
    public RestTemplate regularRestTemplate(String toLog) {
        return new RestTemplateBuilder().setConnectTimeout(100)
                                        .setReadTimeout(100)
                                        .additionalInterceptors((request, body, execution) -> {
                                            log.info("Inside the interceptor {}", toLog);
                                            return execution.execute(request, body);
                                        })
                                        .build();
    }
    @Bean("exceptionalRestTemplate")
    public RestTemplate regularRestTemplate() {
        return new RestTemplateBuilder().setConnectTimeout(100)
                                        .setReadTimeout(100)
                                        .build()
    }
}

Then, I have a class that should use the bean called exceptionalRestTemplate.

@Component
class Client {
    private RestTemplate restTemplate;
    @Autowired
    public Client(@Qualifier("exceptionalRestTemplate") RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
    // Code that uses the injected rest template
}

Since I specified the name of the bean I want to be injected using the @Qualifier annotation, I would expect that Spring injects the bean called exceptionalRestTemplate. However, the bean called regularRestTemplate is actually used during the injection process.

It turns out that the problem was in the name of the methods that declare the beans in the configuration class. Both are colled regularRestTemplate. Changing the second method name, solve the problem.

My question is, why? I know that Spring uses the names of classes and methods annotated with the @Bean or with the @Component, @Service, etc... annotations to give a name to Java object inside the resolution map. But, I supposed that giving a name inside these annotations would override this behaviour.

Does anybody tell me what's going on?

1
The methods function as factory methods and in the ConfigurationClassBeanDefinitionReader this is handled specially. Doing this in 2 seperate @Configuration annotated classes would work.M. Deinum

1 Answers

5
votes

Bean qualifier and bean name are different meanings. You qualified new bean but tried to override it (arguments don't matter). In your application, you cannot override beans so you have the only first one.

You can check this 'theory'. Add a parameter in your configuration

spring.main.allow-bean-definition-overriding=true

and start your application again. After that, you will have only a second bean.

This is an explanation of the collision. But the solution is a separation of beans to different configurations.