Last updated: April 24, 2025
Working with Spring applications often involves managing numerous configuration properties across multiple files. A common challenge developers face is how to efficiently filter and access properties that share a common prefix. If you’ve ever found yourself repeatedly writing ${abc.hibernate.property}
for dozens of properties, this guide is for you.
Spring property prefix filtering allows you to extract all properties with a specific prefix without manually referencing each one. This technique can significantly reduce XML bloat and make your configuration more maintainable.
Table of Contents
- Understanding the Property Prefix Challenge
- Method 1: Creating a Custom PrefixedProperties Class
- Method 2: Using Reflection to Access PropertyPlaceholderConfigurer
- Method 3: Implementing a Custom PropertiesFactoryBean
- Comparing the Different Approaches
- Best Practices for Property Management
- Conclusion
Understanding the Property Prefix Challenge
In Spring applications, we often use PropertyPlaceholderConfigurer
to load property files:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>a.properties</value>
<value>b.properties</value>
<value>c.properties</value>
</list>
</property>
</bean>
These property files might contain numerous entries with a common prefix:
abc.hibernate.show_sql=true
abc.hibernate.default_schema=myschema
abc.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
abc.hibernate.format_sql=true
abc.hibernate.hbm2ddl.auto=validate
When configuring beans that need these properties (like a Hibernate SessionFactory
), you would typically need to reference each property individually:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="hibernateProperties">
<util:properties>
<prop key="hibernate.show_sql">${abc.hibernate.show_sql}</prop>
<prop key="hibernate.default_schema">${abc.hibernate.default_schema}</prop>
<prop key="hibernate.dialect">${abc.hibernate.dialect}</prop>
<prop key="hibernate.format_sql">${abc.hibernate.format_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${abc.hibernate.hbm2ddl.auto}</prop>
</util:properties>
</property>
</bean>
This approach is verbose and prone to errors. Let’s explore three better solutions for Spring property prefix filtering.
Spring property prefix filtering simplifies configuration management by automatically extracting properties with common prefixes
Method 1: Creating a Custom PrefixedProperties Class
The first approach involves creating a custom class that extends java.util.Properties
to filter properties by prefix:
import java.util.Enumeration;
import java.util.Properties;
public class PrefixedProperties extends Properties {
public PrefixedProperties(Properties props, String prefix) {
if (props == null) {
return;
}
Enumeration<String> en = (Enumeration<String>) props.propertyNames();
while (en.hasMoreElements()) {
String propName = en.nextElement();
String propValue = props.getProperty(propName);
if (propName.startsWith(prefix)) {
String key = propName.substring(prefix.length());
setProperty(key, propValue);
}
}
}
}
To use this class in your Spring configuration:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="hibernateProperties">
<bean class="com.example.PrefixedProperties">
<constructor-arg ref="props"/> <!-- reference to all properties -->
<constructor-arg value="abc.hibernate."/> <!-- prefix -->
</bean>
</property>
</bean>
This approach requires you to make your properties available as a bean, which you can do using PropertiesFactoryBean
or Spring’s utility namespace.
Method 2: Using Reflection to Access PropertyPlaceholderConfigurer
Another approach leverages reflection to access and filter the properties loaded by PropertyPlaceholderConfigurer
:
public static Properties filterProperties(String prefix, PropertyPlaceholderConfigurer ppc) {
Properties props = new Properties();
Method method = ReflectionUtils.findMethod(PropertiesLoaderSupport.class, "mergeProperties");
ReflectionUtils.makeAccessible(method);
Properties all = (Properties) ReflectionUtils.invokeMethod(method, ppc);
for (String key : all.stringPropertyNames()) {
if (key.startsWith(prefix))
props.setProperty(key.substring(prefix.length()), all.getProperty(key));
}
return props;
}
This can be used with Spring’s SpEL (Spring Expression Language):
<bean id="ppc" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- configuration -->
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="hibernateProperties" value="#{T(com.example.PropertyUtils).filterProperties('abc.hibernate.', @ppc)}" />
</bean>
Method 3: Implementing a Custom PropertiesFactoryBean
The third approach creates a custom FactoryBean
that loads and filters properties:
public class PrefixedPropertyFactoryBean extends AbstractFactoryBean<Properties> {
private List<Resource> locations;
public void setLocations(List<Resource> locations) { this.locations = locations; }
private String prefix;
public void setPrefix(String prefix) { this.prefix = prefix; }
@Override
public Class<?> getObjectType() { return Properties.class; }
@Override
protected Properties createInstance() throws Exception {
Properties properties = new Properties();
for (Resource resource : locations) {
properties.load(resource.getInputStream());
}
Properties filteredProps = new Properties();
for (String key : properties.stringPropertyNames()) {
if (key.startsWith(prefix)) {
filteredProps.setProperty(key.substring(prefix.length()), properties.getProperty(key));
}
}
return filteredProps;
}
}
You can use this factory bean in your Spring configuration:
<bean id="hibernateProps" class="com.example.PrefixedPropertyFactoryBean">
<property name="locations">
<list>
<value>classpath:a.properties</value>
<value>classpath:b.properties</value>
<value>classpath:c.properties</value>
</list>
</property>
<property name="prefix" value="abc.hibernate." />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="hibernateProperties" ref="hibernateProps" />
</bean>
Comparing the Different Approaches
Each Spring property prefix filtering method has its advantages:
- Custom PrefixedProperties Class: Simple to implement but requires properties to be exposed as a bean.
- Reflection Method: Directly accesses properties from
PropertyPlaceholderConfigurer
but relies on internal Spring APIs that could change. - Custom PropertiesFactoryBean: Most flexible but requires loading properties again, potentially duplicating work.
The best approach depends on your specific requirements and constraints.
Best Practices for Property Management
Regardless of which method you choose, consider these best practices for managing prefixed properties in Spring:
- Use consistent prefix naming conventions across your application
- Document the purpose of each prefix in your codebase
- Consider using Spring Boot’s relaxed binding for more modern applications
- For complex property structures, consider switching to YAML format which supports hierarchical configurations
Conclusion
Spring property prefix filtering techniques can significantly reduce configuration boilerplate and improve the maintainability of your Spring applications. The three methods outlined here provide flexible options for different scenarios, allowing you to choose the approach that best fits your needs.
By implementing one of these solutions, you can eliminate repetitive property references and make your Spring configuration more concise and easier to maintain.
Have you implemented any of these approaches in your Spring applications? Or do you have another method for handling prefixed properties? Share your experience in the comments below!
If you found this guide helpful, check out our other Spring tutorials: