spring-boot and ./config directory - java

I'm not certain anymore about how Spring-boot exactly handles environment, properties file and config location.
Use case
Below the result docker container of my spring-boot application
Docker container
/
|- spring-boot-app.jar
|- /config/
|--|- application.properties
|--|- logback-spring.xml
I also use environment variables
The problem
The logback-spring.xml isn't read by Spring-boot.
To make it so I HAVE TO add LOGGING_CONFIG=config/logback-spring.xml
Shouldn't Spring-boot look for logback-spring.xml automatically under this directory ?
Thank you

In the Spring Documentation (https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html) it says:
The various logging systems can be activated by including the
appropriate libraries on the classpath, and further customized by
providing a suitable configuration file in the root of the classpath,
or in a location specified by the Spring Environment property
logging.config.
So if you put the file directly beneath spring-boot-app.jar it should work without configuration of logging.config.

Spring boot automatically loads application.properties and application.yaml from below locations, Values from lower-order overriding earlier ones
The classpath root
The classpath /config package
The current directory
The /config subdirectory in the current directory
Immediate child directories of the /config subdirectory

Related

How to springboot custom configuration file path?

Since my project has multiple environments and multiple small project groups, I need to handle the corresponding business logic according to different property names, but I can't find any parameter in bootstrap.yml that can set the custom configuration file path.
After I googled, I only found a way to modify the path of the custom configuration file through the startup class
Is there any other better way for me to configure it? Please help me!
Spring Boot look for your externalized configuration file in four predetermined
locations :
in classpath root,
in the package /config in classpath,
in the current directory
in /config subdirectory of the current directory.
i think you want to load configuration file from /config folder.
You can programmatically tell Spring Boot to load your configuration files from
custom location as below :
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(Application.class)
.properties("spring.config.name:application,conf",
"spring.config.location:classpath:/your/location/of/config/folder,classpath:/another/location/of/congig/folder")
.build().run(args);

SpringBoot application with multiple application.properties running under Tomcat

I need two application.properties in my Spring Boot App.
I know that using the annotation #PropertySource I can specify more than 1 property files.
I tried to use: #PropertySource({"classpath:application.properties","classpath:external.properties"})
The idea of it is having application.properties with the machine independent properties and this file will be included inside the war file.
The other file (external.properties), will leave in the machine, and won't be included in the war file. Here I want to leave properties like the database connection and so on.
I've already changed catalina.properties for adding the external.properties location into the classpath, but unfortunately when running on Eclipse it doesn't work (complains about the missing database properties.).
If the external properties file will be available in a known location on the machine, then have an environment variable, system property, or command-line argument set up with the path to the file. Then, reference the file in you #PropertySource annotation using file: rather than classpath:
Example: #PropertySource("file:${CONF_DIR}/external.properties")
References:
Spring boot docs on external configuration
PropertySource documentation
Blog post regarding PropertySource

How to use external configuration files with Spring boot deployed in Tomcat 8.5

My Spring Boot application (2.1.1.RELEASE) is deployed as a WAR in a Tomcat 8.5 server under a Debian 9 system. It uses, among others, the following files to configure the application :
myApplication.properties (main configuration file for Spring)
log4j2.xml
Both are under src/main/resources.
My question is about how to configure Tomcat and Spring Boot in a way that allow me to have a directory /home/oliver/conf which contains both of these files, in order to override the defaults defined under src/main/resources (which are then in WEB-INF/classes in the exploded WAR).
Below are the steps I've taken.
First, and as a requirement for the project I'm working on, I changed the default Tomcat base directory to point to another place by editing /etc/init.d/tomcat8 :
CATALINA_HOME=/usr/share/tomcat8
CATALINA_BASE=/home/oliver
My /home/oliver/conf folder, which holds the Tomcat and Spring configs, looks like this :
- Catalina/
- context.xml
- web.xml
- server.xml
- ...
- myApplication.properties
- log4j2.xml
- otherAppConfFile.properties
- ...
Because Spring looks for application.properties by default, I'm using the #PropertySource annotation to specify another file :
#SpringBootApplication
#PropertySource({classpath: myApplication.properties})
public class MyApp extends SpringBootServletInitializer {...}
I've tried to add -Dspring.config.location=file:/home/oliver/conf/myApplication.properties to JAVA_OPTS defined in /etc/default/tomcat8, and it works (overrides the embedded file correctly), but for instance if I try to add file:/etc/oliver/conf/log4j2.xml to the previous JVM parameter, it doesn't work.
I read a bit about Spring "environment profiles" but don't wish to use them if possible.
When I launch Tomcat and issue a ps aux | grep tomcat command, I see all the JAVA_OPTS parameters defined as expected, and I also see the following :
-classpath :/home/oliver/conf:/usr/share/tomcat8/bin/.... -Dcatalina.base=/home/oliver -Dcatalina.home=/usr/share/tomcat8
I'm a bit confused about the way Tomcat's classpath and Spring's are related, and how I should solve this issue.
If the classpath I see at launch includes the /home/oliver/conf directory, why are the files inside not overriding the embedded property files (myApplication.properties, log4j2.xml ...) ? Is the folder seen and added to Spring's classpath ?
EDIT :
As a side note, there might be a variety of files under /home/oliver/conf which would need to be taken into account, for instance log4j2.xml + myApplication.properties + keystore.jks so I'm not sure I can rely on -Dspring.config.location and -Dlogging.config entirely.
What I understand from your question is that you are trying to do something like this.
-Dspring.config.location=file:/etc/oliver/conf/log4j2.xml
I think the property spring.config.location is to provide the location of a properties file for configuration and not log4j2.xml.
You can set the location of the log file in myApplication.properties by setting the value for logging.config like
logging.config=file:/etc/oliver/conf/log4j2.xml
Or else you can try
-Dlogging.config=file:/etc/oliver/conf/log4j2.xml
UPDATE
This is what I do in my production systems. Create a file setenv.sh and enter below command.
export JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStore=/path/to/keystore/keystore.jks -Djavax.net.ssl.trustStorePassword=changeit -Dspring.profiles.active=qa -Dspring.config.location=/path/to/config/ -Dfws_log=/path/to/logfile/location -Xms512m -Xmx1024m -Dsecret.key=somesecretkey"
You can add any number of key value mappings in this file and all of them will be loaded when your tomcat starts.

separate application.properties from .war for tomcat container

When I use executable .jar for my project, I can put my application.properties file into same folder as my .jar, and all my property values will be reading from extended application.properties file.
My question is: It is possible to make like this for .war and tomcat server?
[UPDATE]
The answer is: On standalone tomcat you would have to put an application.properties in <tomcat>/bin
Thanks to #Strelok
You can run your application with spring.config.location property set to the path to your properties file using the file: protocol:
# will look for /etc/myapp/application.properties
-Dspring.config.location=file:/etc/myapp/
# will look for /etc/myapp/custom.properties
-Dspring.config.location=file:/etc/myapp/custom.properties
Default config locations that are always searched:
file:./config/
file:./
classpath:/config/
classpath:/
There is a lot more info in the Externalized Configuration section of the documentation for Spring Boot.
Refer Tomcat Class loader for your version of Tomcat to understand what all class loaders are available. Depending upon that, you can add your application properties files to Shared or Common class loader by keeping it in appropriate directory and adding that directory into the class loader entry in catalina.properties file. Tomcat 7 documentation does not show shared classloader, but catalina.properties does have a placeholder for that. If shared works, go for that instead of common Tomcat 7 Classloader

Using two yaml files for configuration properties

We are using a spring boot application, where properties are loaded from application.yml file instead of application.properties, located at src/main/resources/ which looks like below:
config:
host: localhost:8080
server: 123
And they are being pulled in a .java file like this
#ConfigurationProperties( prefix="config")
public class ConnectionImpl implements Connection{
#Value("${config.host}")
private Stringhost;
}
I am able to retrieve properties this way.
But we are trying to move the config properties from application.yml to a different .yml file which is located at a different location. (src/main/resources/env-config).
Now I am not able to retrieve properties same way, i.e, using #Value annotation. Is there any other annotation I need to add ?
From the documentation:
SpringApplication will load properties from application.properties (or application.yml) files in the following locations and add them to the Spring Environment:
A /config subdirectory of the current directory.
The current directory
A classpath /config package
The class path root
If you don’t like application.properties as the configuration file name you can switch to another by specifying a spring.config.name environment property. You can also refer to an explicit location using the spring.config.location environment property (comma-separated list of directory locations, or file paths).
The default search path classpath:,classpath:/config,file:,file:config/ is always used, irrespective of the value of spring.config.location. This search path is ordered from lowest to highest precedence (file:config/ wins). If you do specify your own locations, they take precedence over all of the default locations and use the same lowest to highest precedence ordering. In that way you can set up default values for your application in application.properties (or whatever other basename you choose with spring.config.name) and override it at runtime with a different file, keeping the defaults.
You need to supply a command line argument that tells SpringApplication where specifically to look. If everything in resources/ is added to the classpath root, then your command line would look like:
java -jar myproject.jar --Dspring.config.location=classpath:/env-config/service-config.yml
If you have a general application.yml under resources/, the properties in there will still be loaded but will take a lower precedence to the properties file specified on the command line.
Your question doesn't really say what you intend to do, but if you want to have a different configuration for different environments (e.g. development, test, production), there is a simple solution for that.
Place your config files in a file hierarchy like this inside your project:
src/
main/
resources/
application.yml
application-development.yml
application-test.yml
application-production.yml
When you now start your application with
java -jar mySpringApplication.jar -Dspring.profiles.active=development
the configuration from application.yml will be taken as a "base layer", overridden by the configuration in application-development.yml. By this, you can have "default" settings for all environments in application.yml and environment-specific configuration in the application-ENV.yml files. The same works for test and production.
No.
You'll be in a much better position if you avoid hard-coding file path like that within your code base. #ConfigurationProperties used to have a locations attribute but it's deprecated and already removed in 1.5.
In Spring Boot, you configure the Environment which is a single source of truth for your configuration. Rather than having settings buried in code, you should configure Spring Boot to read the files that you want. Read the documentation for spring.config.location. If you want to do this in a more transparent manner, perhaps EnvironmentPostProcessor is what you need

Categories