Updated answer:
You can follow the practice in my original answer, but we recently dropped this for a simpler and cleaner option that is more standard (the "Java" way). We made the change because we needed to dynamically load dependent libraries at runtime that were not available at compile time (in their exact version). In our case we wanted to load dependent jars only from separate folder(s) and not from an executable jar. We ended up having duplicate dependencies in the executable jars and in separate folder(s), so we decided to drop the executable jar Properties Launcher and instead only load dependencies from separate folders. This is often NOT the best option and should be evaluated for your use case. I prefer reading the standard Java classpath.
To run a Spring Boot app without an executable jar, we used Maven Assembly to put the dependent jars in a /libs directory and dropped the spring-boot-maven-plugin. The steps and some code for this are below:
- Remove the spring-boot-maven-plugin that creates the executable jar in ZIP format
Add the following to your assembly XML
<dependencySets> <dependencySet> <outputDirectory>where you want the libs to go</outputDirectory> <useProjectArtifact>whether you want to include the project artifact here</useProjectArtifact> </dependencySet> </dependencySets>Run your code from the main class and include the dependent jar folder(s) on the classpath. Use the standard classpath notation on your OS and not the custom, awkward PropertiesLauncher loader path syntax
java -cp <standard-classpath> <main-class>
An example of an actual call:
java -cp $CLASSPATH:./lib/*:./cfg/*:my-app.jar Application.class
In this way you execute the Spring Boot app via standard java execution call, no custom Spring loading syntax. You just need to ensure that all of your dependencies are available on the classpath at runtime. We found this much easier to maintain and made this the standard for all of our apps.
Original answer:
After some researching, and thanks to @TuyenNguyen's helpful answer I was able to get the following working:
I added the following to my spring-boot-maven-plugin so that when I run from the command line it uses the PropertiesLauncher instead of the JarLauncher:
<configuration>
<mainClass>${mainClass}</mainClass>
<layout>ZIP</layout> //THIS IS THE IMPORTANT PART
</configuration>
See here and here for more about the PropertiesLauncher options. It allows you to set the classpath, among other things.
See here, here, and here for where I found the answer to this problem. Using format ZIP makes the PropertiesLauncher be used.
From there, I was able to use this command to launch the application as I intended:
java -Dloader.path=../config,../ -Dloader.config.location=classpath:application.properties -jar ../app-exec.jar
Another important note: when specifying the -Dloader.path make sure to use comma-separated values and only directories and files, as described here. Also, be sure to put the -D args before you specify -jar jar or they will not be set.
If anyone has any suggestions or edits to further improve this answer or the original question in order to help additional users, please let me know or make the edits yourself!
Answer from wrslatz on Stack OverflowUpdated answer:
You can follow the practice in my original answer, but we recently dropped this for a simpler and cleaner option that is more standard (the "Java" way). We made the change because we needed to dynamically load dependent libraries at runtime that were not available at compile time (in their exact version). In our case we wanted to load dependent jars only from separate folder(s) and not from an executable jar. We ended up having duplicate dependencies in the executable jars and in separate folder(s), so we decided to drop the executable jar Properties Launcher and instead only load dependencies from separate folders. This is often NOT the best option and should be evaluated for your use case. I prefer reading the standard Java classpath.
To run a Spring Boot app without an executable jar, we used Maven Assembly to put the dependent jars in a /libs directory and dropped the spring-boot-maven-plugin. The steps and some code for this are below:
- Remove the spring-boot-maven-plugin that creates the executable jar in ZIP format
Add the following to your assembly XML
<dependencySets> <dependencySet> <outputDirectory>where you want the libs to go</outputDirectory> <useProjectArtifact>whether you want to include the project artifact here</useProjectArtifact> </dependencySet> </dependencySets>Run your code from the main class and include the dependent jar folder(s) on the classpath. Use the standard classpath notation on your OS and not the custom, awkward PropertiesLauncher loader path syntax
java -cp <standard-classpath> <main-class>
An example of an actual call:
java -cp $CLASSPATH:./lib/*:./cfg/*:my-app.jar Application.class
In this way you execute the Spring Boot app via standard java execution call, no custom Spring loading syntax. You just need to ensure that all of your dependencies are available on the classpath at runtime. We found this much easier to maintain and made this the standard for all of our apps.
Original answer:
After some researching, and thanks to @TuyenNguyen's helpful answer I was able to get the following working:
I added the following to my spring-boot-maven-plugin so that when I run from the command line it uses the PropertiesLauncher instead of the JarLauncher:
<configuration>
<mainClass>${mainClass}</mainClass>
<layout>ZIP</layout> //THIS IS THE IMPORTANT PART
</configuration>
See here and here for more about the PropertiesLauncher options. It allows you to set the classpath, among other things.
See here, here, and here for where I found the answer to this problem. Using format ZIP makes the PropertiesLauncher be used.
From there, I was able to use this command to launch the application as I intended:
java -Dloader.path=../config,../ -Dloader.config.location=classpath:application.properties -jar ../app-exec.jar
Another important note: when specifying the -Dloader.path make sure to use comma-separated values and only directories and files, as described here. Also, be sure to put the -D args before you specify -jar jar or they will not be set.
If anyone has any suggestions or edits to further improve this answer or the original question in order to help additional users, please let me know or make the edits yourself!
If you don't put your files in src/main/resources then you can put it inside any folder that you want, BUT you must set your folder as a resources folder. Because classpath is always point to resources folder. Once you make your folder as a resource folder, it will be packaged into the jar. If you want to edit your resource file, just using 7 zip tool to open your jar -> edit files -> save -> it will update your change in the jar.
Another solution is create a folder, put all files you want to edit and not packaged in that, then set classpath manually to that folder every time you run, but the way you set above is not correct, try this solution for set classpath correct way.
The Spring Boot Maven Plugin spawns a JVM which will, by default, include whatever your project says should be on the classpath e.g.
${project.build.outputDirectory}this includes classes and resources- dependencies declared in your project's POM
If you need to add things to this classpath, the plugin offers the following:
- addResources
- useTestClasspath
For example, if you want to add this folder: /this/that/theother to the classpath then you would configure the spring-boot plugin as follows:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<folders>
<folder>
/this/that/theother
</folder>
</folders>
</configuration>
</plugin>
With that configuration in place, if you invoke mvn spring-boot:run -X you'll see that the additional folder is included on the front of the classpath ...
[DEBUG] Classpath for forked process: /this/that/theother:...
if you dont want to modify your pom per https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#run.run-goal.parameter-details.directories there are user properties too you can use from command line
in version 2.5.0 +
mvn -Dspring-boot.run.directories=/etc/bbcom spring-boot:run
prior you could use folders
mvn -Dspring-boot.run.folders=/etc/bbcom spring-boot:run
On Linux:
Copyjava -cp MyApp.jar:/home/sleeper/thirdparty/lib -Dloader.main=myMainApplicationClass org.springframework.boot.loader.PropertiesLauncher
On Windows:
Copyjava -cp MyApp.jar;/home/sleeper/thirdparty/lib -Dloader.main=myMainApplicationClass org.springframework.boot.loader.PropertiesLauncher
This will avoid messing with the manifest or the Spring Boot Maven plugin configuration as in the other answers. It will launch your app with the PropertiesLauncher, which allows you to specify the main class in loader.main. As mentioned earlier, for some reason if you use PropertiesLauncher with loader.path, it will not add resource files to the classpath. This works around the issue by using -cp instead of -jar.
EDIT As mentioned by Pianosaurus in the comment, use ":" instead of ";" as separator in the classpath on Linux
If you just want add external libraries you can use the loader.path property.
Copyjava -Dloader.path="your-lib/" -jar your-app.jar
UPDATE
If you also need to read additional files from the classpath you have to create/change the manifest file of your application.
Lets assume that your are initializing your Spring Boot context from the class de.app.Application. Your MANIFEST.MF should looks as follows:
CopyManifest-Version: 1.0
Main-Class: de.app.Application
Class-Path: your-lib/
And the you can simply start your app with java -Dloader.path="your-lib/" -jar MyApp.jar.
For more information about the MANIFEST.MF please see Working with Manifest Files: The Basics.
You can use the loader.path parameter to define a location for an external lib folder. All jars under this folder will be added to the classpath. For example, if you'd like to define C:\extLib as your external lib folder, you can do the following:
java -Dloader.path=/C:/extLib/ -jar aapName.jar
For this to work, you need to use the PropertiesLauncher. There are two ways to do that:
Option 1
Update the project pom.xml and add the following tag:
<configuration> <!-- added -->
<layout>ZIP</layout> <!-- to use PropertiesLauncher -->
</configuration>
Effective build tag, the post-update looks like below:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <!-- added -->
<layout>ZIP</layout> <!-- to use PropertiesLauncher -->
</configuration>
</plugin>
</plugins>
</build>
Option 2
Use the PropertiesLauncher when launching the application from the commandline:
java -cp aapName.jar -Dloader.path=/C:/extLib/ org.springframework.boot.loader.PropertiesLauncher
References:
How to add jars to SpringBoot classpath with jarlauncher
You may refer this below link from spring boot:
https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html#executable-jar-property-launcher-features
You can use the loader.path property to define a lib folder location
I assume what you want is to add your additional resources/configuration files to the classpath in the generated executable jar of Spring Boot. The only off the shelf solution I have found was to use the maven-jar-plugin in addition to the spring-boot-maven-plugin to add the classpath to the manifest, for example:
<!-- setup jar manifest to executable with dependencies -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.3.RELEASE</version>
<configuration>
<fork>true</fork>
<mainClass>Application</mainClass>
<classifier>executable</classifier>
<layout>JAR</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- add configuration to manifest -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifestEntries>
<Class-Path>conf/</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
Note that the class-path will be relative to the generated executable JAR file.
Wouldn't:
java -cp <path to classpath entry> -jar <path to program.jar>
work for you?
You can define your own classpath by the command-line. Lets suppose your jar is myapp.jar and you wand add one extra directory /var/application/config/, so you can execute with the following command line:
java -cp myapp.jar:/var/application/config/ -Dloader.main=myapp.Application org.springframework.boot.loader.PropertiesLauncher
ps: if you are using Windows use ; instead of : to separate your classpath items.
From the Spring Boot Reference Guide, add your config location:
java -jar myproject.jar --spring.config.location=classpath:/var/application/config/