So I have basic multi-module Spring Boot project. The goal, that I had was to build executable jar and pass additional properties with the help of -Dloader.path=....
For some reason (if I understand purpose of this argument) loader.path is being ignored completely.
My project structure is following:
\-
|--conf
|---default
|--pets-api
|--pets-app (this module contains the Main-Class)
|--pets-domain
|--pets-infrastructure
Since no custom active profile is being passed it uses "default". Jar contains application-default.propeties file, that has single configuration server.servlet.context-path=/v1.
/conf/default location has 2 properties files:
application.properties
random.properties - this is bind to #ConfigurationProperties(prefix = "...") inside application
When I run it normally everything is fine java -jar pets-app-0.0.1-SNAPSHOT.jar. It just uses application-default.properties file and that is it.
Now when I am trying to utilize -Dloader.path argument as in java -Dloader.path=PATH/TO/conf/default -jar pets-app-0.0.1-SNAPSHOT.jar it starts application same as before, as if I am not adding 2 more file to classpath.
What is used:
Java 17
Spring Boot 2.6.12
Gradle
Did anyone come across this as well? Any suggestion on how to resolve it?
PS. If there is need to see the code, I can upload it to GitHub.
Related
I explain my problem;
I have a web app developed using Vue.js and Spring Boot, this application working a PDF sheet and saves the file that is generated by Java, I use two lines of code to separate my development part from the production part (I leave you the 2 lines of code like this you understand the concept well)
FileReader leggoFile = new FileReader(System.getProperty("user.dir") + "/temp/webapps/foolder/foolder/file.pdf");
// FileReader leggoFile = new FileReader(System.getProperty("catalina.base") + "/temp/webapps/foolder/foolder/file.pdf");
This whole application is built using the "bootWar gradle plugin" which returns me a .war which I will then upload to a Tomcat server;
My goal is this:
I would like to set a single environment variable so that if I want to build the project I don't have to comment/uncomment that line for example:
FileReader leggoFile = new FileReader({{variableEnvironment}} + "/temp/webapps/foolder/foolder/file.pdf")
my question is this:
How dp Gradle and Spring Boot handle environments? Is there a way to separate environments? Is this possible or should I start thinking differently?
I tried to search on something but unfortunately I was tied to the problem that I don't understand how the .war file is generated through the BootWar Gradle plugin, also searching on the internet I understood that environment Gradle and environment Spring are two separate things but in general even if I know the line of code is wrong in the beginning my question is always the same:
How are environment variables handled in Spring and Gradle?
With Spring Boot, you can add properties to your application by adding an file named application.yaml to your resources folder (src/resources/). In addition you can add properties through application-{profile}.yaml to add properties only for given Spring profiles. For instance application-test.yaml would only be read if "test" is an active profile. When booting up the application, Spring will first read application.yaml, then any profile-specific YAML-files, such that any overlapping properties are replaced.
There are several approaches to injecting the property. A simple solution is to add a field to your component annotated with #Value("${PATH}) and replace PATH with the property's path in the YAML.
There is a Spring Boot 2 app with such a structure:
parent-module
module-1
src
main
java
resources
- application.yml
module-2
src
main
java
resources
- application.yml
Also, module-1 depends on module-2, specified in pom.xml dependencies section.
The problem is that when I specify some properties in module-2's application.yml - they are not visible in main module-1's components (via #Value annotation).
As was answered here seems like module-1's application.yml overrides module-2's application.yml. There is a workaround - if I use name application.yaml in module-2 everything works fine, but I'm going to add more modules and, finally, it's dirty hack.
What I'm doing wrong? Should such an hierarchy of property files specified somehow?
I will be happy to provide more details if it's needed.
Thank you!
Spring Boot is a runtime framework. I understand that your modules are not spring-boot applications by themselves (you can't make a dependency on a spring boot application packaged with spring boot maven plugin, because it produces an artifact that is not really a JAR from the Java's standpoint although it does have *.jar extension).
If so, they're probably regular jars. So you should have a "special" module that assembles the application. This special module lists both 'module1' and 'module2' in <dependency> section and should contain a definition of spring-boot-maven-plugin in its build section (assuming you're using maven). But if so you shouldn't really have more than one application.yml - it will be misleading. Instead, put the application.yml to the src/main/resources of that "special" module.
If you really have to for whatever reason work with multiple application.yaml files, make sure you've read this thread
I know, this is already a well-aged post.
I just came accross the same issue and the best solution I found was to import the module-specific configurations with the spring.config.import directive as described here.
In this case you still have your module specific configuration in property or yaml files within that specific module and do not have too much unwanted dependencies in your project setup.
application.yml is, as the name indicates, an application-level file, not a module-level file.
It is the build script that assembles the final application, e.g. the .war file, that needs to include a application.yml file, if any.
If modules need properties, and cannot rely on the defaults, e.g. using the : syntax in #Value("${prop.name:default}"), they need to provide a module-level property file using #PropertySource("classpath:/path/to/module-2.properties").
Note: By default, #PropertySource doesn't load YAML files (see official documentation), but Spring Boot can be enhanced to support it. See #PropertySource with YAML Files in Spring Boot | Bealdung.
Alternative: Have the application-level build script (the one building the .war file) merge multiple module-level build scripts into a unified application.yml file.
I'm trying to run a java8 app using spring boot version 2.2.4. The app is then packed in a docker image.
The way I run my app as specified in a Dockerfile which ends liek this:
FROM openjdk:8
.....
CMD /usr/local/openjdk-8/bin/java -jar -Dspring.config.location=/opt/$APP/ /opt/$APP/$APP.jar
The problem I encounter is the loading of external properties files.
For example I have application.properties file similar to this, which is packaed inside the JAR:
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=db1
application.queue.sqs.queue_name=somesqs
In addition, I also inject the docker image an addition application.properties file located at /opt/myapp/. This external file is similar to this:
spring.data.mongodb.uri=mongodb://username:password#MONGO_URL:27017/db_name
application.queue.sqs.queue_name=another_sqs
Expected Behavior: the app will load both new another_sqs location, and external mongo connection.
However, Actual Behavior: when reading the logs I can see that t the new sqs url (i.e. another_sqs) is loaded properly, although the new value for mongo connection is discarded and is therefore using the local embedded mongo engine.
I consulted the following post on stackoverflow to try and understand what I am experiencing:
Spring Boot and multiple external configuration files
But for my understanding, when using spring 2.X and above, the -Dspring.config.location should override all other properties file.
Here is where I started debugging:
TRY 1 : I attached into the docker container, cd into /opt/$APP/ where both my app.jar and application.properties are located, executed the following command java -jar app.jar and viola - it works! A connection to the external mongo source is established. This may be explained by the priority of spring loading properties files as specified in spring's docs.
TRY 2 : Attach the container, cd into $HOME/, execute java -jar /opt/$APP/app.jar -Dspring.config.location=/opt/$APP/ - Do not connect to external mongo, however does connects to the another_sqs. Strange thing - only part of the application.properties values are loaded? Isn't it the way spring 1.X works by adding value from multiple files?
TRY 3 : Attach the container, cd into $HOME/, execute java -jar /opt/$APP/app.jar -Dspring.config.location=file:/opt/$APP/applicartion.properties - same behavior.
Try 4: Edited Dockerfile to include the following execution:
CMD usr/local/openjdk-8/bin/java -jar -Dspring.config.location=classpath:/application.properties,file:/opt/$APP/application.properties /opt/$APP/$APP-$VER.jar
And it works again. Both another_sqs and external mongo are loaded properly on "Try 4".
My question is therefore:
Why should I explicitly specify the classpath:/application.proeprties? Isn't -Dspring.config.location=/opt/$APP/ or -Dspring.config.location=file:/opt/$APP/application.properties should be enough?
When you specify -Dspring.config.location=file:/opt/$APP/application.properties you're overriding the default value of config.location with your application.properties. If you want to use another application.properties, but still using the default properties without declaring them you should use
-Dspring.config.additional-location=file:/opt/$APP/application.properties
In this way, config.location will still have the default value and you will load the external properties as an additional-location.
From the Spring Documentation:
You can also refer to an explicit location by using the spring.config.location environment property (which is a comma-separated list of directory locations or file paths).
When custom config locations are configured by using spring.config.location, they replace the default locations
Alternatively, when custom config locations are configured by using spring.config.additional-location, they are used in addition to the default locations.
I have a mvn project packaged as applicationConfig.jar that contains commonly shared properties across different other projects (WAR's(web application eg: application.war) and JAR's(batch eg: applicationBatch.jar)).
I have used propertysourcesplaceholderconfigurer using annotation to initialize these properties in my applicationConfig.jar
This applicationConfig.jar is now added as dependency in pom.xml's for application.war & applicationBatch.jar
1) The java code in application.war is able to access properties initialized by code executed in applicationConfig.jar on server startup property. No issues here.
2) The applicationBatch.jar which is run from command line on linux machine, is unable to access properties. It appears like the properties initialization code is never executed, when the applicationBatch.jar is run.
Can anyone please help how can i ensure, code sitting in Jar file (applicationConfig.jar responsible for initializing properties using propertysourcesplaceholderconfigurer), is executed, when a batch jar (applicationBatch.jar) is run from command line.
Code Snippet Below:
applicationConfig.jar:
[Attachment ][1]
[Property referenced using annotation and property from properties file][2]
Spring will manage InternalConfig if you import it using #Import or have configured component scan with a base package parent of the InternalConfig one. applicationBatch seems to miss one of this method.
Could you check that ?
I am using IntelliJ and jus checked out working code from the svn.I am struggling to run the jar.
Its a simple core java Spring project.
Since I get the above error.I understand that the spring path is not set fine.
How do I handle it.?
private ApplicationContext appContext = new AnnotationConfigApplicationContext(ApplicationRepositoryConfiguration.class);
Application context file is a bean class here (#Bean annotation is used). I am not using a xml file.
It seems like you are running your project from command line. Run following command :
java -classpath spring.jar;spring-sec.jar,......so on com.example.UrMainClass
while specifying jar in command, make sure you provide complete path of jar. Also check this link https://stackoverflow.com/a/10122038/1065180