Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load a properties file based on the server environment with spring so that the values can be injected?

Tags:

java

spring

To my surprise I have had a difficult time finding an answer to this question. I have Seen many examples where you can use @PropertySource to load a specific properties file for a class. I have also seen examples where you can easily add different property files in spring boot projects. But what I want to do is to do this for a spring project that is NOT spring boot and load a properties file so that the values of this file can be injected in classes annotated with @Component which is dependent on the server environment. So for example if I am on development server I want a particular properties file loaded and on production a different properties file. The reason that I am doing it like this is because my data and service layers are their own modules. These modules contain their own unit tests and can be imported as their own modules in other spring boot projects. I need properties files to be loaded to serve these modules which use spring but not spring boot. I have tried the following, but this does not work.

@Configuration
@Profile("test")
@EnableJpaRepositories("com.hi.repository")
@EnableTransactionManagement
@EnableScheduling
public class InfrastructureConfig  {
...
    @Bean
    public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        Map<String, String> env = System.getenv();
        String propertiesFile=null;

        String e = env.get("SERVER_ENV");

        if (e.equals("dev")) {
            propertiesFile = "environment/development.properties";
        } else if (e.equals("prod")) {
            propertiesFile = "environment/production.properties";
        }

        configurer.setLocation(new ClassPathResource(propertiesFile));


        return configurer;

    }

Then I have a test which looks like this

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/spring/DealServiceTest-context.xml"})
@ActiveProfiles("test")
public class LogTest {

    private static final Logger log = LogManager.getLogger(LogTest.class);

    @Autowired
    PathsService pathsService;

    @Autowired
    Environment environment;


    @Test
    public void testBeans(){
        System.out.println("********** WASSUP from LogTest");
        System.out.println(environment.getProperty("imageBucket"));

    }

Although the test prints out null which indicates to me the properties file has not been loaded and prepared for its values to be injected. How can I achieve this?

like image 919
Dan Avatar asked Sep 06 '17 17:09

Dan


People also ask

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 property values can be injected directly into your beans in spring boot?

Most people know that you can use @Autowired to tell Spring to inject one object into another when it loads your application context. A lesser known nugget of information is that you can also use the @Value annotation to inject values from a property file into a bean's attributes.

How dynamically load properties file in spring boot?

Show activity on this post. 1- Register a Properties File via Java Annotations. 2- Dynamically select the right file at runtime. Show activity on this post.


2 Answers

You don't really need to set properties yourself, but you can do this using spring configuration. Check the documentation: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties

If you're using spring boot - all you need to do is create multiple properties file for your environments. And only for properties you need to override.

So your main properties file would be at

src/main/resources/application.properties

Production

src/main/resources/application-prod.properties

Development

src/main/resources/application-dev.properties

Testing

src/main/resources/application-test.properties

And then just use the profile name as your environment variable

java -jar -Dspring.profiles.active=prod demo-0.0.1-SNAPSHOT.jar
like image 57
Zilvinas Avatar answered Oct 20 '22 18:10

Zilvinas


Actually, you can just use a placeholder in @PropertySource annotation. See documentation:

Any ${...} placeholders present in a @PropertySource resource location will be resolved against the set of property sources already registered against the environment.

Assuming that placeholder is present in one of the property sources already registered, e.g. system properties or environment variables, the placeholder will be resolved to the corresponding value.

I've made a simple example, it receives a 'property.environment' value to choose, which .properties file should be used as property source. I have two resource files in my classpath - application-test.properties and application-dev.properties, each one contains a 'test.property' value ('test-env' and 'dev-env' respectively).

Property configuration:

@Configuration
@PropertySource("classpath:/config/application-${property.environment}.properties")
public class PropertyConfig {
    
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
       return propertySourcesPlaceholderConfigurer;
    }        
}

Component with @Value

@Component
public class TestService {
        
    @Value("${test.property}")
    String testProperty;
    
    @PostConstruct
    void init() {
        System.out.println("---------------------------------------------------------");
        System.out.println("Running in " + testProperty + " environment");
        System.out.println("---------------------------------------------------------");
    }
}

Build command line example (it runs tests with test environment properties)

mvn clean install -DargLine="-Dproperty.environment=test"

Output

---------------------------------------------------------
Running in test-env environment
---------------------------------------------------------

Run command line example

java -jar -Dproperty.environment=dev PATH_TO_YOUR_JAR.jar

Output

---------------------------------------------------------
Running in dev-env environment
---------------------------------------------------------
like image 10
Anatoly Shamov Avatar answered Oct 20 '22 18:10

Anatoly Shamov