I am currently working on a spring-library that allows user-defined config-classes (has nothing to to with @Configuration) to be adjusted from another part of the application before they are used:
interface ConfigAdjuster<T extends Config<T>> {
void adjust(T t);
}
abstract class Config<T extends Config<T>> {
@Autowired
Optional<ConfigAdjuster<T>> adjuster;
@PostConstruct
private void init() {
//i know this cast is somewhat unsafe, just ignore it for this question
adjuster.ifPresent(a -> a.adjust((T)this));
}
}
This can be used as follows:
class MyConfig extends Config<MyConfig> {
public String myData;
}
@Configuration
class MyConfigDefaults {
@Profile("dev")
@Bean
public MyConfig devDefaults() {
//imagine setting defaults values here
return new MyConfig();
}
}
Now a consumer of the library that uses MyConfig can do the following somewhere in his application:
@Bean
public ConfigAdjuster<MyConfig> adjustDefaults() {
return cfg -> {
cfg.myData = "something_other_than_default";
}
}
The biggest problem I see with this approach is that the whole "adjust the config"-part is somewhat hidden for the user. You can not easily tell you are able to change the default-configuration by using a ConfigAdjuster. In the worst case the user tries to autowire the config object and tries to modify it that way which results in undefined behaviour because other components could already have been initialized with the defaults.
Is there an easy way to make this approach more "telling" than what it is right now? The whole idea is to not copy&paste the whole default-config + adjustment parts across multiple projects.
One way to make all of this more explicit would be to require the adjuster in the constructor of Config, but this pollutes every constructor and usage of the inherting classes.
Any thoughts on this?
Aucun commentaire:
Enregistrer un commentaire