Introduction:

The @PropertySource annotation in Spring provides a convenient and declarative mechanism for reading properties files. Properties files contain key-value pairs, e.g. app.log.level = DEBUG. In this article, you will learn to read a value from the property file using @PropertySource and access the specific values using @Value annotation and Environment field.

If you are new to Spring, make sure you understand the basics of Dependency Injection.

1. Use @PropertySource in conjunction with @Configuration

The @PropertySource annotation is used in conjunction with @Configuration annotation. It is also possible to define property source in an XML file. When we have a property file in the classpath or inside resources, we can specify as below.

AppConfig
@Configuration
@PropertySource("classpath:app.properties")
@ComponentScan("com.jsbd.propertysource")
public class AppConfig {
  //other stuffs
}

2. Access the value using @Value annotation

We will read the property file using @PropertySource and access a value from this file using @Value("${}").

ConnectionManager
@Component
public class ConnectionManager {

  @Value("${app.database.url}")
  private String url;
  
  @Value("${app.database.username}")
  private String username;
}

The complete example is shown below.

AppConfig
package com.jsbd.propertysource;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource("classpath:app.properties")
@ComponentScan("com.jsbd.propertysource")
public class AppConfig {
}
ConnectionManager
package com.jsbd.propertysource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.StringJoiner;

@Component
public class ConnectionManager {

  @Value("${app.database.url}")
  private String url;

  @Value("${app.database.username}")
  private String username;

  @Value("${app.database.password}")
  private String password;

  @Value("${no.value}") //No value found
  private String noValue;

  @Override
  public String toString() {
    return new StringJoiner(", ", ConnectionManager.class.getSimpleName() + "[", "]")
        .add("url='" + url + "'")
        .add("username='" + username + "'")
        .add("password='" + password + "'")
        .add("noValue='" + noValue +"'")
        .toString();
  }
}
TestClass
package com.jsbd.propertysource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestClass {
  public static void main(String[] args) {

    ApplicationContext context
        = new AnnotationConfigApplicationContext(AppConfig.class);
    System.out.println(context.getBean(ConnectionManager.class));
  }
}
application.properties
app.database.url=http://random-url
app.database.password=abcd@123
app.database.username=root

Output:

ConnectionManager[url='http://random-url', username='root', password='abcd@123', noValue='${no.value}']

3. Use @PropertySource with Environment

The official spring doc recommends to use Environment interface to access any property from a properties file.

AppLogger
@Component
public class AppLogger {

  @Autowired //Use setter/constructor based injection
  private Environment env;
  
  public void printLogLevel() {
    String logLevel = env.getProperty("app.log.level");
    System.out.println(logLevel);
  }
}

4. Specify multiple property sources using @PropertySources

It is possible to specify multiple property sources as well in Spring now.

ApplicationConfig
	@Configuration
	@PropertySources({
		@PropertySource("classpath:app.properties"),
		@PropertySource("classpath:db.properties")
	})
	public class ApplicationConfig {
		//...
	}

If one or more specified PropertySource file is not found, spring will throw an Exception.

5. Ignore a Property file if not found

Occasionally, you may want the app to ignore the property source not found exception. Spring throws an exception when a specified file is not found.

Caused by: java.io.FileNotFoundException: 
    class path resource [persistence.properties] cannot be opened because it does not exist
AppConfig
@Configuration
@PropertySource(value="classpath:persistence.properties", ignoreResourceNotFound=true)
public class AppConfig {
    //...
}

6. Placeholder resolution

The Environment is integrated throughout the Spring container, it allows the resolution of placeholders through it. Below is an example that shows the import of an xml config file and the name of this file is dynamically injected.

AppConfig
@Configuration
@ImportResource("classpth:${app.name}.xml")
public class AppConfig {
    //extra stuff here
}

It does not matter who provides the app.name value, this will work. Lets say instead of assigning this value from properties file, we assign it using the jvm parameter, this will work.

java -jar -Dapp.name="jpa-example" JpaApp.jar
Remember:

  • The @PropertySource annotation is repeatable, according to Java 8 conventions.
  • However, all such @PropertySource annotations need to be declared at the same level, either directly on the configuration class or as meta-annotations within the same custom annotation.
  • Mixing direct annotations and meta-annotations is not recommended since direct annotations effectively override meta-annotations.

Conclusion:

It is simple to use the @PropertySource annotation in Spring. Access the values using @Value("${property.name}") and the Environment interface. Let me know your feedback on this article. You can find the complete example below.


By |Last Updated: April 2nd, 2024|Categories: Spring Framework|

Table of Contents