I want to push the Spring-application on jarniki, pushing the entire configuration infrastructure into one jarnik. It turns out something like this:

backend-base.jar -> backend-auth-service.jar backend-base.jar -> backend-file-service.jar 

Inside backend-base.jar is the @Configuration class, which configures oscsPropertySourcesPlaceholderConfigurer , which, in turn, must be set to default values ​​(which are divided into backend-base.jar and dependent on the first jar). How to do it right? Is it possible to somehow declare an interface and find all its implementations in the current package in order to use it to declare classes of default values?

There is an option to scan the package, but, of course, the original jarnik should not be aware of its dependencies.

    1 answer 1

    As a result, everything turned out to be implemented as follows:

    I threw out the configuration method offered by the spring, despite the fact that it has a number of advantages. Instead, I created a simple Settings class that wraps a simple HashMap<String, Object> :

     public class Settings { public boolean exists(String key) { ... } public Object get(String key) { ... } public void set(String key, Object value) { ... } } 

    ApplicationSettings class, which is a settings aggregator and another HashMap wrapper:

     public class ApplicationSettings { public boolean exists(String key) { ... } public Object get(String key) { ... } public <T> T get(String key, Class<T> targetType) { ... } public void set(String key, Object value) { ... } public void setAll(Settings settings) { ... } } 

    Interface SettingsProvider:

     public interface SettingsProvider { Settings getSettings(); } 

    and the @DefaultSettingsProvider annotation, by which the default data sources are located:

     public @interface DefaultSettingsProvider { // а ничего тут и нет } 

    After that, I created another ApplicationSettingsFactory class that does three things:

    1. Finds all annotated @DefaultSettingsProvider implementation of the SettingsProvider and alternately stuffs the data inside it in ApplicationSettings (the search class with the hell name ClassPathScanningCandidateComponentProvider and the root package of the application containing all the other classes are used for the search)
    2. Finds all configuration files (application.properties, application.local.properties, application.% Profile%. Properties, application.% Profile%. Local. Properties) and also stores them in the same instance of ApplicationSettings
    3. It launches two post-processors, which in turn search for redefinitions of certain settings in -D properties and, finally, in environment variables.

    From the advantages of this approach:

    • It was possible to implement the desired hierarchy of settings, thanks to which the application runs on a dev machine with just the “expected settings” and is easily configured in the docker container using normal environment variables (the 12-factor app was satisfied).
    • With proper operation, you can create your beans not with fixed settings, but pull them up every time (or once every N time) from ApplicationSettings. This allows you to change settings on the fly and introduce, for example, new nodes for replication, which the spring from the box could not allow.
    • It turned out to implement the nyashny console settings command, which displays all the settings of the application and facilitates debag.
    • The configuration key is set by a constant, which is then reused in @DefaultSettingsProvider, which eliminates the possibility of a mistake.

       @Configuration public class RedissonConfiguration { public final static String REDIS_URI_SETTINGS_KEY = "service.redis.uri"; public Redisson redisson(ApplicationSettings settings) { String redsUriRepresentation = settings.get(REDS_URI_SETTINGS_KEY, String.class); ... } } @DefaultSettingsProvider public RedissonDefaultSettingsProvider implements SettingsProvider { public static final String REDIS_URI = "redis://localhost:6379"; public Settings getSettings() { Settings settings = new Settings; settings.set(RedissonConfiguration.REDIS_URI_SETTINGS_KEY, REDIS_URI); return settings; } } 

      Spring uses SpEL, which I don't need, but which for obvious reasons requires wrapping the names of the settings in @Value using ${} , which is overkill for me.

    • Due to the fact that in the concept of a spring it is just a bin being created, during initialization there are no problems in the inaccessibility of any low-level application services, initialization of static fields, etc.

    Of the minuses:

    • Still, we could not avoid scanning the entire package of the application as a whole.
    • In case I have a plug-in configuration (for example, Redis, which is not needed in all child microservices), then @DefaultSettingsProvider will still pull values ​​from it. In the future, maybe I’ll just create a configuration annotation indicating where the default settings are for it.