Friday, 11 November 2016

How to read properties file in Spring Framework

There are scenarios when you have to provide few configuration properties in order to configure the resource like in case of Database you need to provide driver class, DB location, user name and password or in case of sending mail through your application you need to provide properties like SMTP host, user name, password.

Many a times developers put all these details in the Spring XML configuration file itself which is not a good practice. It’s better to put them in a properties file that way you can have specific properties files like db.properties, mail.properties, app.properties etc. That way any change in any setting will require you to change the specific properties file only.

In Spring setting property values by reading a properties file can be done using -

  • XML configuration
  • Using @PropertySource Annotation

Using XML configuration

Suppose you have your Database properties in a properties file called db.properties residing under config folder under resources folder.

db.properties (for connecting to MYSQL DB)

db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/netjs
db.username=root
db.password=password
pool.initialSize=5

Then you can use ${property key} placeholders in <bean> definitions. In order to resolve these placeholders you must register a PropertySourcesPlaceholderConfigurer. This happens automatically when using <context:property-placeholder> in XML.

Full XML configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
   
     <!--  For reading properties files --> 
    <context:property-placeholder location="classpath:config/db.properties" />
    
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
        <property name="dataSource" ref="dataSource"></property>  
    </bean>  
    <bean id="employeeDAO" class="org.netjs.daoimpl.EmployeeDAOImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>  
    </bean>
    
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value = "${db.driverClassName}" />
        <property name="url" value = "${db.url}" />
        <property name="username" value = "${db.username}" />
        <property name="password" value = "${db.password}" />
        <property name="initialSize" value = "${pool.initialSize}" />
    </bean>

</beans>

Using @PropertySource Annotation

Spring also has @PropertySource annotation (added in Spring 3.1) for reading properties file. It can be used with @Value annotation to read the value of the given property.

Example Program

Given a file db.properties (as used above)containing the key/value pair, the following @Configuration class uses @PropertySource along with @Value annotation to read properties.

import org.apache.commons.dbcp2.BasicDataSource;
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:config/db.properties")
public class DBConfig {
    @Value("${db.driverClassName}")
    private String dbDriverClass;
    @Value("${db.url}")
    private String dbUrl;
    @Value("${db.username}")
    private String dbUser;
    @Value("${db.password}")
    private String dbPwd;
    
    @Bean
    public BasicDataSource dataSource() {
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName(dbDriverClass);
        ds.setUrl(dbUrl);
        ds.setUsername(dbUser);
        ds.setPassword(dbPwd);
        return ds;
    }
    
    //register PropertySourcesPlaceholderConfigurer
    //in order to resolve ${...} placeholders
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
        return new PropertySourcesPlaceholderConfigurer();
    }
} 

Here you can see how fields are annotated with @Value(property key name) annotation in order to map them with the specific property in the .properties file.

In order to resolve ${...} placeholders in <bean> definitions or @Value annotations using properties from a PropertySource, one must register a PropertySourcesPlaceholderConfigurer. This happens automatically when using <context:property-placeholder> in XML (in above example), but must be explicitly registered using a static @Bean method when using @Configuration classes. That’s what is done in DBConfig class.

If you want to run this you can use the following class -

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

public class App {

 public static void main(String[] args) {
  AbstractApplicationContext context = new AnnotationConfigApplicationContext(DBConfig.class);
  BasicDataSource ds = (BasicDataSource)context.getBean("dataSource");
  System.out.println("URL - " + ds.getUrl());
 }

}

Using with Spring’s Environment

Rather than using @Value annotation, Environment should be used to read properties file. Actually @PropertySource annotation adds a PropertySource to Spring's Environment so that can be used to make your code simpler.

Example with Environment

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;


import org.springframework.core.env.Environment;

@Configuration
@PropertySource("classpath:config/db.properties")
public class DBConfig {
 @Autowired
 private Environment env;
 
 @Bean
 public BasicDataSource dataSource() {
  BasicDataSource ds = new BasicDataSource();
  System.out.println("User " + env.getProperty("db.username"));
  ds.setDriverClassName(env.getProperty("db.driverClassName"));
  ds.setUrl(env.getProperty("db.url"));
  ds.setUsername(env.getProperty("db.username"));
  ds.setPassword(env.getProperty("db.password"));
  return ds;
 }
}

In that case you just need to Autowire (or Inject) Environment into your Config class and use Environment object to get property value.

property overriding with @PropertySource

In cases where a given property key exists in more than one .properties file, the last @PropertySource annotation processed will 'win' and override. For example, given two properties files a.properties and b.properties, consider the following two configuration classes that reference them with @PropertySource annotations:

 @Configuration
 @PropertySource("classpath:/com/myco/a.properties")
 public class ConfigA { }

 @Configuration
 @PropertySource("classpath:/com/myco/b.properties")
 public class ConfigB { }

The override ordering depends on the order in which these classes are registered with the application context.

Using ignoreResourceNotFound

In case your properties file is optional and not having it should not throw exception you can use ignoreResourceNotFound and set it as true. Default is false.

As example

If you want to load test.properties file and want to ignore the resource if not found then you can do it as -

@Configuration
@PropertySource(value="classpath:config/test.properties", ignoreResourceNotFound=true)
public class DBConfig {
 @Autowired
 private Environment env;
 ..........
 ..........

That's all for this topic How to read properties file in Spring Framework. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Data access in Spring framework
  2. Configuring DataSource in Spring Framework
  3. Select query using JDBCTemplate in Spring framework
  4. How to inject prototype scoped bean in singleton bean
  5. @Resource annotation in Spring autowiring

You may also like -

>>>Go to Spring tutorial page

No comments:

Post a Comment