Spring boot - Loading configuration property file in to java.util.properties - java

I need to load a configuration property fully into java.util.Properties file in my spring boot project and then need to pass this wherever needed. With Spring boot I can load the full file and can get the access of the values though keys. But how I can load the whole configuration file into Properties object or pass the spring loaded property (not a single value rather all the values) wherever required?
My current code:
Properties myProps= new Properties();
myProps.load(resourceAsStream);

If you're looking for specific ways of loading them using Spring-boot I'd suggest looking into:
Binding properties to an object by using the #Configuration, #ConfigurationProperties and #PropertySource annotations if you want to enforce and implicitly manage type-safety at all times
The Environment interface you can #AutoWire to your classes, if you don't need to enforce type-safety at all times (you can still do it, but you're not forced to). #PropertySource can be used in this case as well to load properties outside the default default-loaded application.properties, although they'll be loaded only when the application context refreshes (e.g. they won't be available while the application is booting up)
The PropertiesLoaderUtils class, as suggested in the comments, if you want to selectively load a configuration file at runtime for example
I usually recommend the first. The result is the same as using an #AutoWired Environment, with the advantages of implicit type-safety and improved readability. You can then get the properties and write them inside your java.util.properties if you need them to be there.
However, there is more than one way to do that, both using Spring-Boot or not. Loading properties like that is also perfectly fine, although arguably not the best practice since you're using Spring-boot.

Related

Use Spring properties loading without initializing the Spring context

I love the Spring properties loading mechanism. The fact that you can define several profiles and override or extend properties with other profiles, that you can use different file types (.properties, XML, JSON, ...) to store your properties, that you can use the value of other properties to resolve its own value, aso.
But to use the properties, you have to somehow initialize the Spring context (#SpringBootApplication or #SpringBootTest). And I would like to use this property loading mechanism in some libraries, where I cannot guarantee that the context is loaded (and I do not want to load it).
So, my question:
Can I somehow create a class that uses the Spring libraries to load the properties (on demand) in the same way Spring loads its properties?
Other classes will then use this class to access the properties. No need to load with annotations.
I was searching for this for some time, but I haven't found a solution, yet.
Would be great if so. knows a solution for that.
Regards, stay healthy and merry X-Mas!
The property lookup mechanism is defined by interface PropertyResolver, extended by interface Environment to support profiles, further extended by interface ConfigurableEnvironment to support PropertySources, i.e. the concept of searching through a set of property sources to find a property.
It is implemented e.g. by class StandardEnvironment, which defines property source for:
system properties
system environment variables
All the above are part of package org.springframework.core.env, i.e. part of the spring-core-XXX.jar file.
Support for application.properties files is added by class ConfigFileApplicationListener in package org.springframework.boot.context.config.
The class needs an instance of SpringApplication in package org.springframework.boot.
They are part of the spring-boot-XXX.jar file.
So, getting basic Spring property support is easy, just create a StandardEnvironment object.
Getting application.properties files loaded is deeply embedded in the Spring Boot code, and would be really difficult to do without initializing the Spring context.

Where to define properties in SpringBoot which are common across all environments?

I have few properties common to all environments (Ex. spring.jpa.properties.hibernate.ejb.interceptor) which I have kept in application.properties under resource directory.
I have DB properties defined in environment based properties file which I pass externally through command line while starting the app:
java -jar -Dspring.config.location=<path-to-file> mySpringBootProject.jar
However, spring.jpa.properties.hibernate.ejb.interceptor is not being set when I am passing properties file externally.
Do I need to define common properties even in external file?
Or is there a way I can define them in a single place which is reused when not overridden?
You can use multiple profiles to do this. For example, create property files:
application-dev.properties
application-prod.properties
application.properties
Place your environment-specific properties in the application-${env}.properties file and your common properties in application.properties.
There are multiple ways to tell spring which profiles to use, for example the --spring.profiles.active flag.
See the Spring Boot documentation for more details about the property file search order.
application.properties will normally be overridden by Boot projects. Instead, you can add a properties file in a non-conflicting location (such as src/main/resources/my/package/foo.properties) and use #PropertySource on your autoconfiguration file to add it.
Properties is a file extension for files mainly used in Java related technologies to store the configurable parameters of an application. The advantage of using properties file is, we can configure things which are environment specific (or are prone to change over a period of time) without the need of changing anything in code. Hence inheriting common properties is not a good approach. If a property seems to be static for all e.g. environments, then it shouldn't be a property.
But, it could be we have multiple development environments and production, where we would share same properties in the environments meant for development purposes and different properties for production. In this case we could create a common properties file and inherit it in all our environment specific properties files. Another scenario could be, that at the moment of development the property is same for all environments, but we would like to provide the option of changing it in the future, when required.

Get list of Spring property placeholder and their resolved values

I would like to make all property placeholder and their resolved values of a running Spring (Boot) application available for process monitoring. In the first step this could be just by writing them to the logs or by creating a 'resolved.properties' file similar to the application.pid file.
All properties where property placeholder are used (implicit/explicit) should be considered.
Motivation: It is usually hard during operation to know the values of resolved properties. System properties or command line arguments are "visible" but e.g. hidden default values in the code (like #Value("${timeout:30000}")) are hard to find out. I would like to be able to answer the question "How does the configuration of the running application looks like?" in a generic way that I can use in all of my spring applications.
I know about the Spring Boot Actuator /configprops endpoint, but this only includes #ConfigurationProperties. I would like to get a list of all properties where placeholder are used.
The requirement does not seem to be new (see here or here) but I wonder if there is an appropriate (bootiful) way nowadays.
There is (currently) no way to obtain all the properties in the Environment abstraction. This is intentional as can be read here. This is also why it isn't possible to obtain all the values used for resolution.
The values and resolutions are logged at runtime telling which key was resolved from where at runtime. But that logging is quite verbose and logged each time a StringValueResolver is used.
You might get a partial result by providing your own customized PropertySourcesPlaceholderConfigurer which maintains a collection of resolved key/value pairs. But not every resolution uses the PropertySourcesPlaceholderConfigurer some directly use a StringValueResolver implementation bypassing the PropertySourcesPlaceholderConfigurer.
It doesn't cover all your needs (ie: properties from all files, default values, application arguments, etc.).
I'll still keep the answer for other readers/future reference.
Spring Boot's Actuator /env endpoint
You may use the /env endpoint. It lists a bunch of stuff but it also includes the content of application.properties (near the end):
applicationConfig: [classpath:/application.properties]={myproperty=blah, server.port=8080}

How to prevent Spring Boot Devtools from caching few files

I am using spring cache to cache my database results, when spring cache is enabled along with spring boot devtools we receive weird exception ClassCastException due to known limitation is spring dev tools.
Now I want to exclude the class which contains cache from auto restart or reload, How we can achieve this?
You can workaround this issue pretty easily.
First of, you can disable caching completely, simply add the following to your configuration:
spring.cache.type=none
You could add that as a system property, or in the run configuration of your IDE so that it only applies when you're using devtools on your box.
Then you can switch to a cache manager implementation that does not serialize the content of object. One way to achieve that is to create a cache manager in memory with a certain profile:
#Configuration
#Profile("dev")
public DevConfig {
public CacheManager cacheManager() {
return new SimpleCacheManager();
}
}
And then enable the dev profile (again via a property or in the run config of your IDE). This might now work if you have complex eviction rules.
Finally, you can fix the underlying problem by adding (including) the cache library (the component that is responsible of the serialization) in the application classloader. See this link for more details.
The restart technology provided by Spring Boot works by using two classloaders. Classes that do not change (for example, those from third-party jars) are loaded into a base classloader. Classes that you are actively developing are loaded into a restart classloader. When the application is restarted, the restart classloader is thrown away and a new one is created. This approach means that application restarts are typically much faster than “cold starts”, since the base classloader is already available and populated.
By default, any open project in your IDE is loaded with the “restart” classloader, and any regular .jar file is loaded with the “base” classloader. If you work on a multi-module project, and not every module is imported into your IDE, you may need to customize things. To do so, you can create a META-INF/spring-devtools.properties file.
The spring-devtools.properties file can contain properties prefixed with restart.exclude and restart.include. The include elements are items that should be pulled up into the “restart” classloader, and the exclude elements are items that should be pushed down into the “base” classloader. The value of the property is a regex pattern that is applied to the classpath, as shown in the following example:
restart.exclude.companycommonlibs=/mycorp-common-[\\w\\d-\.]+\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w\\d-\.]+\.jar
see Spring boot devtools docs

Pass properties to log4j before it loads

Is there a way to pass data or setting to log4j before it loads and then use that property within the config file.
I was assuming there is a system properties I could use:
log4j.appender.R.File=/usr/local/pfs/logs/${ws.host}/log4j.log
Where ws.host is the property I want to use.
But how can I set that value?
Also, I am in a web environment. How can I know at what point to set the property setting before log4j loads.
The default log4j PropertiesConfigurator supports variable substitution.
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PropertyConfigurator.html
So, you could pass system properties like this "-DmyProject.logFile="/temp/test.log" to your Java startup, and then in the properties files have "log4j.appender.R.File=${myProject.logFile}".
If working from a web environment, you might want to check out Spring's Log4jConfigListener. It uses a listener (Servlet API 2.4+) to initialization log4j ahead of other components. Even if not using Spring, you should be able to use the source as an example to easily create your own listener.

Categories

Resources