Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Value works without configuring static PropertySourcesPlaceholderConfigurer

Tags:

java

spring

I am trying to understand the behaviour of @PropertySource annotation when not using @Autowiring and Spring Environment class. I am trying to use @Value to inject values from a properties file at runtime. From the book that I am reading and from the online sources it is required to have a static bean - PropertySourcesPlaceholderConfigurer configured in order for this to work. But for me the @Value works without PropertySourcesPlaceholderConfigurer static bean as well. Can someone point me to the right direction as to whats happening here. May be I am missing something very basic. When do we need PropertySourcesPlaceholderConfigurer and when not?

Below is the code that I am trying out -

package com.nilaysundarkar.demos;

public class Person {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

AppConfig.java -

package com.nilaysundarkar.demos;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

@Configuration
@PropertySource("classpath:/com/nilaysundarkar/demos/app.properties")
public class AppConfig {

    // This bean does not make any difference, or does it?
    /*@Bean
    public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer(){
        return new PropertySourcesPlaceholderConfigurer();
    }*/

    @Bean
    public Person person(@Value("${person.name}") String name){
        Person person = new Person();
        person.setName(name);
        return person;
    }

}

Bootstrap -

package com.nilaysundarkar.demos;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {

    public static void main(String[] args){

        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Person person = context.getBean(Person.class);
        System.out.println(person.getName());
        ((AnnotationConfigApplicationContext)context).close();
    }

}

properties file - app.properties -

person.name=John Doe

pom -

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nilaysundarkar.demos</groupId>
<artifactId>demos-runtime-injections</artifactId>
<version>0.0.1-SNAPSHOT</version>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>4.0.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
    </dependency>
</dependencies>

When I run App.java -

enter image description here

like image 841
Nilay Sundarkar Avatar asked Apr 08 '17 19:04

Nilay Sundarkar


2 Answers

In spring boot, and spring in general, application.properties (and application.yml since spring boot) can be placed in src/main/resources and it is picked automatically by the spring environment. That means that any property from this files will be loaded to your Environment and will be ready for injection using @Value.

You can use PropertySourcesPlaceholderConfigurer in order to register more property sources like foo.properties, [NAME].properties and so on in order for the spring Environment to add them.

When you use @PropertySource you register another propery file to your spring Environment so you dont need to use the custom PropertySourcesPlaceholderConfigurer to register it again. @PropertySource make it easier to register property files that do not require some special loading like a file in your file system etc.

As long as you use the default locations (application.properties) you don't need to register a custom bean of this type.

EDIT:

Example for PropertySourcesPlaceholderConfigurer with the same functionality as @PropertySource. The example is based on a foo.properties file residing in src/main/resources:

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
    configurer.setLocation(new ClassPathResource("foo.properties"));
    return configurer;
}
like image 153
Tom Avatar answered Oct 22 '22 08:10

Tom


Took Privotal's Spring Core course months ago (probably Feb/2018) and the student handout (Version 5.0.a) explicitly tells you that a static PropertySourcesPlaceholderConfigurer bean must be declared in order for the ${}placeholders to be resolved when using Spring Core. But, when I tested this behavior omitting the creation of the bean in question it worked as If I’d created the bean resolving the placeholders. After that, I contacted my course instructor because I thought there was something wrong with my code, but he later confirmed that my code to be "good". He proceeded to contact Pivotal and we got an official answer :

Properties files registered via @PropertySource are automatically added to the Environment in org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClass, SourceClass) while processing @Configuration classes.

So, apparently Pivotal acknowledge that the documentation on this is poor, and have filed a new JIRA.

BTW, this only applies to Spring Core 4.3+ as Spring Boot creates this bean for you automatically.

EDIT:

If you're taking the certification test, it's not clear when will Pivotal make the update, but the odds of this particular issue showing up on the exam are minuscule (in case it does appears, you can appeal)

like image 2
Cempoalxóchitl Avatar answered Oct 22 '22 09:10

Cempoalxóchitl