1. Overview
By design, classes annotated with @Repository, @Service, @Controller, etc. are managed by Spring and injecting configuration there is easy and natural. What’s not as simple is passing configuration to classes that are not directly managed by Spring.
In that case, we can use *ClassLoader-*based configuration loading or simply instantiate our classes in another bean and set required params manually – this is the suggested option because configuration entries don’t need to be stored in *.properties files exclusively.
In this quick article, we are going to cover the topic of loading *.properties files with Java ClassLoader as well as injection of already loaded configuration by Spring into an unmanaged class.
2. Load Configuration With Class Loader
Simply put, *.properties files are resources files holding some config info. Instead of using third party implementations that support automatic application configuration loading, e.g. that implemented in Spring, we can use Java ClassLoader to do the same.
We’re going to create a container object that will hold Properties defined in resourceFileName. To fill up the container with configuration, we will use a ClassLoader.
Let’s define PropertiesLoader class that implements loadProperties(String resourceFileName) method:
public class PropertiesLoader {
public static Properties loadProperties(String resourceFileName) throws IOException {
Properties configuration = new Properties();
InputStream inputStream = PropertiesLoader.class
.getClassLoader()
.getResourceAsStream(resourceFileName);
configuration.load(inputStream);
inputStream.close();
return configuration;
}
}
Every Class object contains a reference to the ClassLoader that instantiated it; this is an object that is primarily responsible for loading classes, but in this tutorial, we’ll use it for loading resource file instead of plain Java class. The ClassLoader is looking for resourceFileName on the classpath.
Afterward, we load the resource file as InputStream via the getResourceAsStream API.
In the above example, we defined a configuration container that can parse resourceFileName using the load(InputStream) API.
The load method implements parsing of *.properties files with support of “:” or “=” characters as delimiters. Additionally, both “#” or “!” characters used at the beginning of the new line are comment markers and cause that line to be ignored.
Finally, let’s read the exact value of defined configuration entry from our configuration files:
String property = configuration.getProperty(key);
3. Loading Configuration With Spring
A second solution is to make use of Spring Spring feature to handle some of the low-level loading and processing of files.
Let’s define an Initializer that will hold the configuration needed to initialize our custom class. During Bean initialization, the framework will load all of the fields annotated with @Value from *.properties config file:
@Component
public class Initializer {
private String someInitialValue;
private String anotherManagedValue;
public Initializer(
@Value("someInitialValue") String someInitialValue,
@Value("anotherValue") String anotherManagedValue) {
this.someInitialValue = someInitialValue;
this.anotherManagedValue = anotherManagedValue;
}
public ClassNotManagedBySpring initClass() {
return new ClassNotManagedBySpring(
this.someInitialValue, this.anotherManagedValue);
}
}
The Initializer can now be responsible for instantiating the ClassNotManagedBySpring.
Now we’ll simply access our Initializer instance and run the initClass() method on it to handle the instantiation of our custom ClassNotManagedBySpring:
ClassNotManagedBySpring classNotManagedBySpring = initializer.initClass();
Once we have the reference to Initializer, we’ll be able to instantiate our custom ClassNotManagedBySpring.
4. Summary
In this quick tutorial, we focused on reading properties into a non-Spring Java class.
As always, an example implementation can be found over on GitHub.