Small question for SpringBoot, and how to configure the bean using @Qualifier
please.
I have a very straightforward piece of code:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
<relativePath/>
</parent>
<groupId>com.question</groupId>
<artifactId>language</artifactId>
<version>1.1</version>
<name>language</name>
<description>Spring Boot</description>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package com.question;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LanguageApplication {
public static void main(String[] args) {
SpringApplication.run(LanguageApplication.class, args);
}
}
package com.question.service;
public interface LanguageService {
String process(String name);
}
package com.question.service;
import org.springframework.stereotype.Service;
@Service("french")
public class FrenchLanguageServiceImpl implements LanguageService {
@Override
public String process(String name) {
return "Bonjour " + name;
}
}
package com.question.service;
import org.springframework.stereotype.Service;
@Service("english")
public class EnglishLanguageServiceImpl implements LanguageService {
@Override
public String process(String name) {
return "Welcome " + name;
}
}
package com.question.controller;
import com.question.service.LanguageService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
@RestController
public class LanguageController {
private final LanguageService languageService;
@Value("${configuration}")
public String configuration;
public LanguageController(@Qualifier(configuration) LanguageService languageService) {
this.languageService = languageService;
}
@GetMapping("/test")
public String test(@RequestParam String name) {
return languageService.process(name);
}
}
Expected:
What I hope to achieve is equally straightforward. I would like to pass some sort of configuration to application.properties
, something like configuration=french
or configuration=english
.
At the controller layer, to use (@Qualifier(configuration) LanguageService languageService)
And the correct concrete service will be used.
Actual:
Unfortunately,
@Qualifier(configuration) + @Value("${configuration}") public String configuration;
will yield Attribute Value must be constant
.
Is there a way we can configure the concrete Bean via a configurable @Qualifier
please?
I understand there is a way to workaround this by using ApplicationContext getBean.
But having this construct: @Qualifier(configuration) makes the code clean and easily understandable. How to achieve this please?
Thank you
If you only need 1 of the LanguageService
beans active at a time, then you can use @ConditionalOnProperty
on each of them, each using a unique havingValue
. Like this (warning, untested code written from memory):
interface ConfigKeys {
public static final String LANGUAGE = "my.app.prefix.language";
}
@Service
@ConditionalOnProperty(name = ConfigKeys.LANGUAGE, havingValue = "english")
public class EnglishLanguageServiceImpl implements LanguageService {
@Override
public String process(String name) {
return "Welcome " + name;
}
}
@Service
@ConditionalOnProperty(name = ConfigKeys.LANGUAGE, havingValue = "french")
public class FrenchLanguageServiceImpl implements LanguageService {
@Override
public String process(String name) {
return "Bonjour " + name;
}
}
With that, you don't need any qualifiers, just set the my.app.prefix.language
property in your config (application.properties or application.yaml) to the value you want, and there will just one LanguageService
bean in the context. You can inject that bean wherever you need it without needing a qualifier.