Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Import Spring config file based on property in .properties file

In my Spring xml configuration I'm trying to get something like this to work:

<beans>     <import resource="${file.to.import}" />     <!-- Other bean definitions -->  </beans> 

I want to decide which file to import based on a property in a properties file. I know that I can use a System property, but I can't add a property to the JVM at startup.

Note: The PropertyPlaceHolderConfigurer will not work. Imports are resolved before any BeanFactoryPostProcessors are run. The import element can only resolve System.properties.

Does anyone have a simple solution to this? I don't want to start subclassing framework classes and so on...

Thanks

like image 326
nash2000 Avatar asked Oct 05 '09 13:10

nash2000


People also ask

How do you externalize a constants from a Spring configuration file into a properties file?

You can use properties files, YAML files, environment variables and command-line arguments to externalize configuration. Property values can be injected directly into your beans using the @Value annotation, accessed via Spring's Environment abstraction or bound to structured objects.

How do you inject configuration values from the properties file into beans?

Property values can be injected directly into your beans by using the @Value annotation, accessed through Spring's Environment abstraction, or be bound to structured objects through @ConfigurationProperties .

How do you load properties file based on environment in Spring boot?

Environment-Specific Properties File. If we need to target different environments, there's a built-in mechanism for that in Boot. We can simply define an application-environment. properties file in the src/main/resources directory, and then set a Spring profile with the same environment name.

How do I load a properties file in Spring?

@ConfigurationProperties in spring boot is another way to read properties files. Add setters and getters for a member variable. Object of this class holds the content of properties with values. As this class is declared a component, You can use it in the Spring application and use properties files.


2 Answers

This is, unfortunately, a lot harder than it should be. In my application I accomplished this by doing the following:

  1. A small, "bootstrap" context that is responsible for loading a PropertyPlaceholderConfigurer bean and another bean that is responsible for bootstrapping the application context.

  2. The 2nd bean mentioned above takes as input the "real" spring context files to load. I have my spring context files organized so that the configurable part is well known and in the same place. For example, I might have 3 config files: one.onpremise.xml, one.hosted.xml, one.multitenant.xml. The bean programmatically loads these context files into the current application context.

This works because the context files are specified as input the the bean responsible for loading them. It won't work if you just try to do an import, as you mentioned, but this has the same effect with slightly more work. The bootstrap class looks something like this:

 public class Bootstrapper implements ApplicationContextAware, InitializingBean {      private WebApplicationContext context;     private String[] configLocations;     private String[] testConfigLocations;     private boolean loadTestConfigurations;      public void setConfigLocations(final String[] configLocations) {         this.configLocations = configLocations;     }      public void setTestConfigLocations(final String[] testConfigLocations) {         this.testConfigLocations = testConfigLocations;     }      public void setLoadTestConfigurations(final boolean loadTestConfigurations) {         this.loadTestConfigurations = loadTestConfigurations;     }      @Override     public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {         context = (WebApplicationContext) applicationContext;     }      @Override     public void afterPropertiesSet() throws Exception {         String[] configsToLoad = configLocations;          if (loadTestConfigurations) {             configsToLoad = new String[configLocations.length + testConfigLocations.length];             arraycopy(configLocations, 0, configsToLoad, 0, configLocations.length);             arraycopy(testConfigLocations, 0, configsToLoad, configLocations.length, testConfigLocations.length);         }          context.setConfigLocations(configsToLoad);         context.refresh();     } } 

Basically, get the application context, set its config locations, and tell it to refresh itself. This works perfectly in my application.

Hope this helps.

like image 118
Louis Marascio Avatar answered Oct 02 '22 12:10

Louis Marascio


For the Spring 2.5 and 3.0, I have a similar solution to louis, however I've just read about 3.1's upcoming feature: property management, which sounds great too.

like image 42
István Avatar answered Oct 02 '22 12:10

István