My question is another question about configuration in spring boot (v 2.2.x) but I have one significant difference in my config structure in comparison to configuration in existing posts on SO about configs (i.e. spring boot external config) I have following application configurations:
--src\
--main\
--resources\
-- application.yml
-- application-local.yml
-- application-dev.yml
-- application-prod.yml
My application-prod.yml looks like:
spring:
profiles:
active: prod
include:
customization
logging:
level:
root: INFO
org.springframework: INFO
org.hibernate.SQL: INFO
org.hibernate.type: INFO
pattern:
console: '%d{yyyy-MM-dd HH:mm:ss} - %msg%n'
file: '%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n'
file: ./logs/goals-service.log
My prod config have to use (this is a business requirement) external configuration with setting of
db connection,
security settings
endpoints and credentials of other services.
I would like to use standard approach and ability of spring to automatically config beans, i do not want to manually load some property file and configure all beans manually. Therefore to solve this issue i created another config application-customization.yml and link it in prod config via include (see in example above). And here i faced a problem: i am unable to select path to application-customization.yml via command line argument (-Dspring.config.location or any it variations) , but i could load customization settings when i placed my external config in directory that is used to start app (this is a behaviour of spring to search configs), and app in this case works fine. I would like to pass path of where app should search my application-customization.yml, and one more thing i can'not use symlinks from to link from actual config location to ./application-customization.yml.
Remove that "include" from your application-dev, because I have no idea how it will interact with anything that I'm going to say. Then there are (at least) two simple ways to do what you want. (There are also some complicated ways -- overkill for your situation, and indeed most situations -- like overriding this or defining one of these.)
Way 1: pass -Dspring.config.location=X to the JVM, where X is a comma-separated list of locations containing files Spring should read. In your case, you probably want -Dspring.config.location=file:/some/folder/,classpath:/; the first location will ensure you fulfill your business requirement and the second will ensure the app also reads the application-dev.yml inside its own jar.
Way 2: put #PropertySource("file:/some/folder/application.properties") on a class annotated with #Configuration (note that #SpringBootApplication is meta-annotated with #Configuration). This has two issues: one, the file in the #PropertySource is read last and the properties therein do not override properties which were read earlier; two, there are some properties which you cannot set with an #PropertySource file (because the file is read too late in the startup process). I don't think either issue will bother you, but I wanted to note them for other readers.
Note on Tomcat (and presumably other containers): using way 1 there is a bit complicated, since spring.config.location is a system property; it might require faffing about with app-specific web.xml files. EDIT 2020-09-04: Or you could do this (specifically the third snippet in that code, which I repeat, modifying the property name and value, in case that answer ever vanishes:
public class ServletInitializer extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class).properties("spring.config.location: /my/config1/,/my/config2/");
}
}
)... which is better.
This answer has mostly been a regurgitation of the excellent official documentation on this and related questions.
Related
I am being new to the spring-boot application, I have a scenario where I need to add a string as a prefix for existing loggers in the current application. I tried this solution, but it didn't work for me. Can anyone help me out with this?
ex: logger.info("Started Test Application...") ==> Started Test Application...
need to add a string of "Amigo" as a prefix ==> Amigo Started Test Application...
mostly I wanted to add that string to all existing logs at one go. any simple solution instead of adding manually to all loggers.
It's a little unclear what your current log setup is, but I'll assume you've got a vanilla out of the box spring boot logging (using default logback impl, no logging config in place).
First, the ref doc for this is found here: https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/boot-features-logging.html
What you're trying to do is customize the pattern or layout. The docs for doing this in logback (the spring boot default logging impl) are here: https://logback.qos.ch/manual/layouts.html
The easiest way is to add the property logging.pattern.console to your application.properties. Note that if you have an additional logging config in your app (e.g. there's a file named logback.xml or similar in your app) this won't work.
The default console pattern for spring boot is, I believe,
%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${sys:PID} --- [%15.15t] %-40.40logger{1.} : %m%n%wEx
So to Add what you want would be something like:
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${sys:PID} --- [%15.15t] %-40.40logger{1.} : Amigo %m%n%wEx
Note, I haven't tested this so you may need to fiddle a bit.
Is it possible to use Spring Boot so that all configurations are explicitly in the main class?
For example, is it possible to tell spring-boot to print all autoconfigurations make by #SpringBootApplication so that I can copy paste in my main class?
Or is it possible to copy then from somewhere into the main?
You can have Spring Boot create a report (a list of auto configurations) simply by enabling debug mode in your application.properties file:
debug = true
The auto-configuration report contains information about the classes that Spring Boot found on the classpath and configured automatically. It also shows information about classes that are known to Spring Boot but were not found on the classpath.
And, because you've set debug=true in application.properties or application.yml, so you will see it in your output.
There is no way of doing this. Either you embrace the devil and suffer the consequences latter if you need to personalize something unpredictable by spring boot developers or you don't use it's magic.
I'm currently using an EnvironmentPostProcessor to add my external PropertySource, the code looks like this :
public class ExternalPropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor
{
private static final String EXTERNAL_PROPERTY_SOURCE_NAME = "ExternalPropertySource";
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application)
{
if (environment.acceptsProfiles(Profiles.EXTERNAL_PROPERTY_SOURCE_ENABLED_PROFILE)) {
environment.getPropertySources()
.addLast(new ExternalPropertySource(EXTERNAL_PROPERTY_SOURCE_NAME, new ExternalSource()));
}
}
}
A spring.factories is also used to register this EnvironmentPostProcessor.
This code actually works if the profile is set in the vm environment variables, but if it is added in src/main/resources/application.yml, the profile doesn't seem to be injected yet in the environment and is not returned by the environment.getActiveProfiles(). I've tried using the interface Ordered with the lowest precedence, but it doesn't help.
To add a bit of context around what I'm trying to achieve, this class is in a small library that adds an external property source like a database. Then we can use it in some other spring boot applications. Something like Spring Cloud Config does.
I'd like a clean way to enable or disable this property source depending on the environment where the code runs. I don't mind using something else then profiles or even another way to inject the property source, I just want something clean that doesn't depend on several factors to work.
The main problem in my code right now is that I'm using spring boot's property sources to make my own property source configurable.
UPDATE : I used a Spring Cloud app to debug this, and was confusing the bootstrap context with the normal spring boot context. See my answer below.
Further investigation made me figure out the problem appeared only with a Spring Cloud application.
In fact the breakpoint I had in this code was triggered twice, once after the bootstrap context initialization and once after the spring boot context initialization. I was only debugging the profiles in the first occurence. At that point, only the bootstrap.yml properties are loaded and not the ones from the application.yml file. The second occurence obviously had the profiles from my application.yml file.
My code worked as expected with a vanilla Spring Boot application. As the documentation states :
The Environment has already been prepared with all the usual property
sources that Spring Boot loads by default.
I was confused by the behaviour of my app which seemed to be different from that statement, but it was Spring Cloud's bootstrap that was messing with my debugging.
Since I need a PropertySource that has the highest precedence, I need to add it in the post bootstrap initialization for Spring Cloud apps. I used an init flag on my EnvironmentPostProcessor so it doesn't get executed twice and used the bootstrap.yml on Spring Cloud apps to set the profile.
TL;DR :
With Spring Cloud, an EnvironmentPostProcessor gets called twice: once after the bootstrap init and once after the normal Spring Boot context init. If you need injected properties and are targeting the Spring Cloud's post bootstrap initialization, use the bootstrap.yml instead of application.yml.
I have a spring boot application and I want to use both a yml file for my application properties and also a plain application-${profile}.properties file set to configure my application.
So my question is can this be done and if so, how do you configure spring boot to look for both the yml file and the properties and merge them into one set per environment?
As to why I want/need to use both, it is because I like the flexibility and ease of use of yml files but an internal component (for encryption) requires using the properties file set.
I did see this point being made YAML files can’t be loaded via the #PropertySource annotation
but nothing stating whether both can be used together.
Please provide detailed configuration (XML or Java config) on how to get this working.
TIA,
Scott
I can answer my own question, as it just works as you would expect. The application.yml file and the appropriate application-${profile}.properties both get loaded and merged into the environment. Spring boot just makes this work naturally.
Yes You can use both at same time in same project.
When you use both YML and properties at same time, say for example
application.yml and application.properties at same time in same
project, first application.yml will be loaded, later
application.properties will be loaded.
Important point to be noted is that if application.yml and
application.properties have same keys for example in
application.yml has spring.app.name = testYML and
application.properties has spring.app.name = testProperties at same
time in same project, then application.yml value will be overwritten
by application.properties value since it is loading at last.
And the value in spring.app.name = testProperties.
Yes, you can run both without doing any configuration.
In Spring Boot, it picks .properties or .yaml files in the following sequences :
application-{profile}.{properties|yml}
application.{properties|yml}
I have a web application consisting of severals modules. All the modules are packaged together in one single ear.
One of them is a brand new groovy app, while others are more old school. This new grails app is not under my responsibility.
Notice that grails is not using any log4j.[properties|xml] file, but it as its own DSL which interact directly with log4j at runtime. This configuration is located inside a config.groovy script, packaged with the application.
Log4j is configured using an external file and the -Dlog4j.configuration option for the JVM.
The problem is the grail configuration is containing a very liberal config:
- set the root level to info
- add a console appender
The result is that the external configuration is hijacked by grails:
now there are two console appender (logging twice the same info) and lots of useless info data are logged.
Is there another solution than a programmatic approach, to tell grails to stop being rude ?
You could just turn off the grails logging so it uses the external logger
http://blog.saddey.net/2010/02/07/grails-how-to-use-native-server-logging-configuration-eg-tomcat-glassfish-jboss/