Reputation:
I'm building a web service that needs to switch between two sets of properties depending on the request URL coming in. I'm not sure which is the best method of handling this.
I've got a Spring Boot app that has an yaml properties file. Inside the properties file the structure looks something like this;
optionA:
foo:
urls:
- a
- b
bar:
something: hello
optionB:
foo:
urls:
- x
- y
bar:
something: bye
Both optionA
and optionB
have pretty much all the same properties, just different values.
So a request comes in, I check the request and decide if I need optionA or optionB.
I've been trying to get @ConfigurationProperties
to handle this but the properties are initialised on startup so it can't be dynamic. Another possibility is that I have two Configuration classes, one for each option but then my code gets full of checks to switch between the two classes and the classes are pretty much identical, not really nice either.
Any best practices or recommendations on how to best manage this would be appreciated, cheers!
Upvotes: 11
Views: 1121
Reputation: 12754
If you have not too many options I would go this way: (Just made example with smaller config)
options.yml:
optionA:
name: optionA
optionB:
name: optionB
I created a Option class for extension:
public class Option {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And two Option classes where the @ConfigurationProperties
are getting set: (For now these classes are empty but you have the opportunity to be more specific on each different option)
@Component
@ConfigurationProperties(prefix ="optionA", locations = "classpath:options.yml")
public class OptionA extends Option{
}
@Component
@ConfigurationProperties(prefix ="optionB", locations = "classpath:options.yml")
public class OptionB extends Option{
}
For the decision of the different options I created an interface
:
public interface OptionService {
Option findOption(boolean businessLogic);
}
And in the implementation I inject both options and the implementation of the business logic: (in an easy way)
@Service
public class OptionServiceImpl implements OptionService {
private OptionA optionA;
private OptionB optionB;
@Override
public Option findOption(boolean businessLogic) {
if(businessLogic){
return getOptionA();
} else {
return getOptionB();
}
}
public OptionA getOptionA() {
return optionA;
}
@Autowired
public void setOptionA(OptionA optionA) {
this.optionA = optionA;
}
public OptionB getOptionB() {
return optionB;
}
@Autowired
public void setOptionB(OptionB optionB) {
this.optionB = optionB;
}
}
And at the end your controller just call the OptionServiceImpl
class and deceide which option should be used:
@Controller
public class YourController {
private OptionService optionServiceImpl;
@RequestMapping("/")
public String getIndex(){
Option option = getOptionServiceImpl().findOption(true);
System.out.println(option.getName());
option = getOptionServiceImpl().findOption(false);
System.out.println(option.getName());
return "Hello World";
}
public OptionService getOptionServiceImpl() {
return optionServiceImpl;
}
@Autowired
public void setOptionServiceImpl(OptionService optionServiceImpl) {
this.optionServiceImpl = optionServiceImpl;
}
}
Output of System.out.println:
optionA
optionB
So your business logic to decide which option should be used is not an if - else construct. You are able to create the rules for the decission in the interface and its implementation. I think you are able to create more rules for more controllers.
Upvotes: 2
Reputation: 7072
Change your yml to:
options:
- name: optionA
foo:
urls:
- a
- b
bar:
something: hello
- name: optionB
foo:
urls:
- x
- y
bar:
something: bye
Add Config class:
@Data
@ConfigurationProperties
@Configuration
public class MyConfig {
private List<Option> options;
}
Use it:
@Component
public class UseConfig {
@Autowired
public UseConfig(final MyConfig config) {
System.out.println(config.getOptions());
}
}
Result:
[Option(name=optionA, foo=Foo(urls=[a, b]), bar=Bar(something=hello)), Option(name=optionB, foo=Foo(urls=[x, y]), bar=Bar(something=bye))]
Upvotes: 1
Reputation: 5283
You can define key value pairs in application.properties.
where key is web service name and value is option(list of properties)
Make use of @ConfigurationProperties
@ConfigurationProperties
class Configuration {
Map<String,Option> options;
// getters and setters
}
@Component
class ChooseServiceBasedConfiguration {
@Autowired
Configuration configuration;
public void serviceMethod(String key ){
//get appropriate properties of the web service
configuration.getOptions().get(key);
}
}
based on web service get the values required using the key .
Upvotes: -1