It’s never a good practice to hard code and combine any environment related details such a username, password or file path etc. along with spring bean configuration. Usually in Java we will be having those details written in a separate property file and it will be read during the execution, the same can be followed in the spring as well using PropertyPlaceholderConfigurer.
Spring comes with a bean factory post processor called PropertyPlaceholderConfigurer which allows you to externalize those details into a properties file. In this Spring PropertyPlaceholderConfigurer Example we will learn how to use the PropertyPlaceholderConfigurer.
Let’s first of all look into the Spring Setter Injection Example and see how PropertyPlaceholderConfigurer externalizes those properties.
Folder Structure:
- Create a new Java Project “SpringCoreTutorial” and create a package for our src files “com.javainterviewpoint“
- Add the required libraries to the build path. Java Build Path ->Libraries ->Add External JARs and add the below jars.
commons-logging-1.2.jar
spring-beans-4.2.4.RELEASE.jar
spring-core-4.2.4.RELEASE.jar
spring-context-4.2.4.RELEASE.jar
spring-expression-4.2.4.RELEASE.jar
ojdc14.jar - Create the Java classes JDBC_Example.java and Logic.java under com.javainterviewpoint folder.
- Place our configuration file SpringConfig.xml in the src directory
JDBC_Example.java
package com.javainterviewpoint; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class JDBC_Example { private String url; private String username; private String password; Connection connection = null; public JDBC_Example() { super(); } public JDBC_Example(String url, String username, String password) { super(); this.url = url; this.username = username; this.password = password; } public void setUrl(String url) { this.url = url; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public void connect() { try { Class.forName("oracle.jdbc.driver.OracleDriver"); connection = DriverManager.getConnection(url, username,password ); PreparedStatement ps = connection. prepareStatement("select * from student"); ResultSet rs = ps.executeQuery(); while(rs.next()) { System.out.println(rs.getString(1)); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); return; } } }
- In our JDBC_Example class we have a three properties url, username, password and its corresponding setter methods whose value will be injected through spring bean xml configuration file via Spring Setter injection.
- We also have a connect() method which will let us connect to the database using a simple java jdbc connection.
Spring Bean XML Configuration file
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config></context:annotation-config> <bean id="jdbc" class="com.javainterviewpoint.JDBC_Example"> <property name="url" value="jdbc:oracle:thin:@rsh2:40051:mydb"></property> <property name="username" value="test"></property> <property name="password" value="test"></property> </bean> </beans>
In our spring bean XML configuration file we have declared a bean for “JDBC_Example” class and through Spring Setter Injection we have injected the values to the properties url, username, password. This way we are hard coding the jdbc details in our Spring bean configuration file.
Logic.java
package com.javainterviewpoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Logic { public static void main(String args[]) { // Read the Configuration file using ApplicationContext ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringConfig.xml"); // Get the JDBC_Example class instance JDBC_Example je = (JDBC_Example) applicationContext.getBean("jdbc"); // Call the connect() method je.connect(); } }
- In our Logic class we have read the Configuration file(SpringConfig.xml) and get all the bean definition through ApplicationContext
- Get the JDBC_Example Class instance by calling the getBean() method over the context created.
- Using the JDBC_Example class instance obtained from above call the connect() method, which in-turn connects us to the Oracle database using Java jdbc connection.
Output:
Once when we run the Logic class we will be getting the below output.
Spring PropertyPlaceholderConfigurer Example
In the above code we have hard coded the jdbc details in the spring bean configuration file, now lets externalize those details into a property file and read it through Spring PropertyPlaceholderConfigurer. Lets create a property file and make some minor tweaks to our bean configuration xml.
jdbc.properties
jdbc.url = jdbc:oracle:thin:@rsh2:40051:mydb jdbc.username = test jdbc.password = test
In our Spring configuration file we will be making the below changes.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config></context:annotation-config> <bean id="jdbcproperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"/> </bean> <bean id="jdbc" class="com.javainterviewpoint.JDBC_Example"> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> </beans>
- We have declared a bean for our PropertyPlaceholderConfigurer and through setter injection of Spring we have injected the location of our properties file (jdbc.properties) to the location property.
- The PropertyPlaceholderConfigurer tells the Spring IoC Container to load the property file which is present in the classpath and resolve any placeholders ${….}
- In our JDBC_Example class bean we have replaced the hard coded jdbc details with the place holders like ${jdbc.url},${jdbc.username} and ${jdbc.password}. Spring replaces these placeholders with the actual values which is present in the property file.
- Exception will be thrown when spring could not resolve a placeholder. If suppose we have removed an entry “jdbc.password = test” from our jdbc.properties file we will be getting the error like below.
How to ignore PlaceHolder Exception ?
As in the above case we have removed the password entry from our jdbc.properties file and we got the exception like below
Could not resolve placeholder ‘jdbc.password’ in string value “${jdbc.password}”
There are cases when we wanted to ignore this property check and proceed, in those cases we can simply put the value as “true” for the property “ignoreUnresolvablePlaceholders”, this will prevent the Spring IoC container to check whether all the property is present or not. In case of a missing property Spring will not throw any exception.
<bean id="jdbcproperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
How to ignore FileNotFoundException ?
If suppose when the required property files is not present in the specified location, then we will be getting java.io.FileNotFoundException, if you want to ignore that also and proceed then you can put the value as “true” for the property “ignoreResourceNotFound”. This will prevent the Spring IoC Container to check whether the properties file is present or not.
<bean id="jdbcproperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
<property name="ignoreResourceNotFound" value="true"/>
</bean>
When ignoreResourceNotFound is set to true, Spring will not be throwing an exception when the property file is not present.
Loading Multiple Property files
We can configure multiple property file as well using the PropertyPlaceholderConfigurer. The “locations” property of PropertyPlaceholderConfigurer can take the List of property files we simply need to give the location of all the files. Lets say we have two property files named ftp.properties and jdbc.properties, then the configuration will be like below.
<bean id="jdbcproperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name = "locations"> <list> <value>classpath:jdbc.properties</value> <value>classpath:ftp.properties</value> </list> </property> </bean>
This makes the spring container to resolve the place holders of both ftp.properties and jdbc.properties
Property File locations
By default Spring IoC Container will be looking for the property file in the application directory(under src directory). You can have it under the sub folders as well, all you have to do is to prefix the property file with the location. If suppose I have moved the property file under “com.javainterviewpoint” package then the configuration will be like
<bean id="jdbcproperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name = "locations">
<list>
<value>com/javainterviewpoint/jdbc.properties</value>
</list>
</property>
</bean>
You can also load the property file from the application classpath, we just need to add prefix “classpath:” which tells spring to load the property file form the application classpath.
<bean id="jdbcproperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name = "locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
Property file can also be loaded from the absolute path using the prefix “file:” or “file:///” both are acceptable
<bean id="jdbcproperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name = "locations">
<list>
<value>file:///c:/jdbc.properties</value>
</list>
</property>
</bean>
Leave a Reply