Override spring-boot application configuration via external property file [duplicate] - java

This question already has answers here:
Spring Boot: Is it possible to use external application.properties files in arbitrary directories with a fat jar?
(12 answers)
Closed 3 years ago.
I want to override few configurations in my spring boot application during a restart via an external configuration file.
What I am using:
java -jar -Dspring.profiles.active=${ENV} my-application.jar
This loads my profile specific application property during application start. Let's assume I have an issue and I need to change the configuration in my application, I don't want to rebuild my application again with the changed property, what I want to achieve is that I provide an external property file which has the new value for the configuration and I restart my application.
I have tried suggestion mentioned here https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-application-property-files
Let's say I copy my jar to bin folder on my server and create a /config folder inside the bin folder which contains the override.properties file and then run the same command as stated above to restart my application.
It doesn't override the property mentioned in override.properties
I tried to provide spring.config.location as a command line argument but then I need to write all my properties in that file which is not what I need.

If you look at the top of Section 24 in the link you cite, you'll see a long list of places that Spring looks for property providers. Have you looked down that list? There are a number of options for providing external properties that override internal ones. Basically, anything higher on the list will override something lower on the list.
One option is to put JSON in the single environment variable SPRING_APPLICATION_JSON. This is what we do for unexpected overrides. We always define this variable in a separate file included by our main startup script, but it is usually empty. But at any time, we can go and add properties to it, and they will take priority and override any existing property values. We chose this option because it has a vey high priority. It is mostly only test code and settings that override these settings. The only other thing that does is properties put on the command line. Those, of course, can be changed without building a new binary.
There are other promising choices on that list, like #14. I believe there are ways of having external properties files that don't replace existing ones, but rather just override them, so that you don't have to redefine all of your existing properties there. I'd be surprised if there was no way to do that...have an external properties file that just overrode a few properties.
UPDATE: The "duplicate" cited in the question comments backs up what I'm saying here. It says very clearly that multiple properties files will override each other. No one file need provide all the properties. So it seems you're on the right track, and just have something wrong with your properties file configuration. Just keep in mind what I'm saying. It may be easier to use some other source than a properties file, like either the single environment variable SPRING_APPLICATION_JSON, or individual environment variables.

Related

Automatically load dependencies into an Eclipse working set

I have 5 packages in my workspace. One is the "core" package that holds the critical java files for my application, and the name of this package also happens to be the name that I want the working set that contains it to be. The other packages in the workspace (4 of them) are on the build path and provide convenience methods and the like. I want to create a working set based on this core package and have all the other packages on its build path automatically enter its working set.
How do I achieve this without manually setting these extraneous packages to the working set, and then manually updating the working set when the dependencies change?
In my real life setting I have numerous working sets I need to manage so this quite quickly becomes overly tedious.
I don't think you can unless you provide an external script. Eclipse help file states
Newly created resources are not automatically included in the active
working set. They are implicitly included in a working set if they are
children of an existing working set element. If you want to include
other resources after you have created them you have to explicitly add
them to the working set.

Combining Application and Server Level logging with Log4J?

Is it possible to work with two different levels of logging simultaneously with Log4J/Tomcat? Here is my situation: I have a few webapps operating on the same Tomcat Server. Some of these applications have their own log4j properties file (legacy).
Something I want to add is a new logger with a JDBCAppender that will work across all of these applications (They're meant to be used together so having them log to the db we've selected would be VERY useful for us.) I've written the properties file entries in order to do this the way I want (and tested in one of those local property files for syntax purposes).
Is it possible to drop this new logger/JDCBAppender in a server-level log4j.properties file, and then have the webapps gain access to it? For instance, if I define the logger as 'com.xxx.yyy', then in any webapp that has a class in a 'com.xxx.yyy' package grab said logger with a call like:
private static Logger logger = Logger.getLogger(MyClass.class);
assuming the full declaration is com.xxx.yyy.MyClass.
I've tried dropping the log4j.properties file in the $CATALINA_HOME/lib directory as well as placing the necessary jar files in the same directory (as directed in the comments below) but when I launch my server, it doesn't seem to pick that one up, although it picks up the one from my webapp. I know the properties file has to be on the classpath for log4j to pick it up, but can there be some sort of similar-class path style issue if there is more than one log4j.properties file?
Update: I've updated the description of what I've tried.
I've done some additional research and learned that if multiple log4j.properties files are on the classpath, the system will use the first it finds, just like with java class/library files.
So in the end, the situation I was describing is not feasible, as adding a Server-level properties file would cause all my individual web-apps' legacy property files to be ignored. It may still be possible to do something similar, but my question was intended to focus specifically on the log4j.properties file.

Apache Java Configuration API - configuration profiles (inheritance)?

When i was working with Zend Framework, I used to have .ini configuration files, where I could do this:
[production]
setting1 = abc
setting2 = def
[development : production]
setting1 = ghi
And when I turned on the development application profile then the setting1 had a value of ghi, whereas in the prdouction mode it was abc. Is is possible to define such inherited settings in Apache Commons Configuration?
I know that I can define multiple configuration files and create a CompositeConfiuration from them, but how to tell the application that it should include only specific files in different modes? I do not also have an idea how to set these application profiles yet but another setting called PROFILE should do the work for me.
If possible, I would not want to split the settings in multiple files.
I can't find any information about how this should be done in Java.
Apache Configuration reads the config options from a file into a memory data structure. Besides variable expansion, there is no further post processing by default. So your options are:
Put all options in a default config and then use individual "delta" configs that overwrite the defaults. Merge these individual files with CompositeConfiuration.
This design follows Java's inheritance model: Base type which you extend to overwrite some value and add new ones.
Create a post processor that takes the huge config and turns that into a new config with your preferred merging rules applied.
Create a helper object to look up values by key in the config. That would allow you do the merging at lookup time.

Dynamically manage two jar files with the same package and class names

I have two jar files from a client, one of which is used for a testing and another for final versions. Currently I put them in different folders and modify the library path when deploying our code, but it would be nice to be able to load both jar files and switch between them dynamically at runtime.
Is this possible?
You can always write your own ClassLoader and chain it with the standard ClassLoader.
http://download.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html
I used this method 10 years ago to load classes that were recieved via sockets and specified in an XML file (via sockets as well). My java program didn't know that the classes even existed before it got the XML file and the classes.
Using OSGi bundles you can do that. Take a look at http://blog.springsource.com/2008/02/18/creating-osgi-bundles/. Search for "multiple versions".
justinjh,
chrisparker2000's suggestion looks to be the most feasible - You have to write a custom classloader, the only change that I can think of is something along the following lines:
1. For the client deliverable jars - say client.dev.jar and client.prod.jar, rename to a different extension and place these in the classpath. Rename to a different extension to prevent the container from loading the contents of the jar.
Using the custom classloader, load the contents on demand, based on the solution offered by chrisparker2000, by placing a small facade on top of the client classes, say ClientClassFactory which based on the environment(dev/prod/anything else) would use the custom classloader to load from either client.dev.otherext or client.prod.otherext .
If you use a build-tool like maven, you can define different jar files (dependencies) for different scopes (test vs production).
You may also use maven profiles to define different set of jar files/versions.

What is the best way to deal with environment specific configuration in java?

I have an application running in tomcat that has a bunch of configuration files that are different for each environment it runs in (dev, testing, and production). But not every line in a config file will be different between environments so there's invariably duplicated information that doesn't get updated if something changes.
Is there a good framework/library that collapses the separate files into one with environment specific blocks? Or some other way of dealing with this?
Assign reasonable default values for all properties in the properties files distributed within your .war file.
Assign environment-specific values for the appropriate properties in webapp context (e.g. conf/server.xml or conf/Catalina/localhost/yourapp.xml)
Have your application check the context first (for the environment-specific values), and fall back on the default values in the app's properties values if no override is found.
A Properties file is what I've always used. It's editable by hand as well as in in your software and the Properties object can read itself in and write itself out to the filesystem. Here's the javadoc page:
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html
If you use maven, you can use it's resource filtering abilities, along with profiles to generate a properties file for each environment you're deploying into.
As an added bonus, maven can also deploy your web app for you.
The duplication is not really a problem, having a central config file the the other files 'extend' is likely to casue more of a headache in the long term.
My advice is to use ant to load (copy and move) the appropriate file(s) into place and then launch the app (bundle into war?). Just have a different task for each environment. So you will have three config files (dev.config, test.config and production.config) which will be moved and overwrite the config in the /WEB-INF folder depending on the task that you are running.
I would suggest to have a separate config file for environment parameters alone if you want to avoid cluttering. Then you will have one more config file to manage. This is a trade off between number of config files vs complexity of each config file.

Categories