I am building a software system to interact with an enterprise software system, using Spring Boot. My system depends on some jars and *.ini files from that enterprise system, so I cannot pack all dependencies in Maven. I would like to be able to run Spring Boot as Executable Jar with embedded Tomcat. I would also like to be able to set the classpath via the command line. So something like:
java -classpath /home/sleeper/thirdparty/lib -jar MyApp.jar
However, -classpath and -jar cannot co-exist. I have tried "-Dloader.path". It was able to load all the jar files under the folder, but not other things, like *.ini files in the folder.
So is there a way we can make -classpath to work with an Spring executable jar with embedded Tomcat?
If you just want add external libraries you can use the loader.path property.
java -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:
Manifest-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.
On Linux:
java -cp MyApp.jar:/home/sleeper/thirdparty/lib -Dloader.main=myMainApplicationClass org.springframework.boot.loader.PropertiesLauncher
On Windows:
java -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
You mentioned that you needed to load *.ini files from an external folder. I had to do something similar, load CSV files from an external folder.
My file structure looked like this
./myapp.jar
./config/file.csv
I was using the ResouceLoader to load the files as:
Resource res = resourceLoader.getResource("classpath:file.csv");
File csvFile = res.getFile();
Start script:
java -Dloader.path="config" -jar your-app.jar
The resource was not loading from the "config" folder as expected. After some research I found out that I had to change my Maven plugin configuration to use ZIP layout.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
</configuration>
</plugin>
This will direct Spring Boot to use PropertiesLauncher, which allows loading external resources from "loader.path".
See this excellent article for more detail.
java -cp C:\jar-path\your-jar-1.2.0.jar -Dloader.main=package-and-main class -Dloader.path=external dependency jar path org.springframework.boot.loader.PropertiesLauncher -Dspring.profiles.active=profile etc -default,test --spring.config.location=external properties file name
If want to define external memory use
java -ms8g -mx8g -cp
java -cp
Differences between "java -cp" and "java -jar"?
-Dloader.main
Spring Boot’s org.springframework.boot.loader.PropertiesLauncher comes with a JVM argument to let you override the logical main-class called loader.main:
-Dloader.path
Tell the PropertiesLauncher that it should pick up any libraries found in the “lib”
org.springframework.boot.loader.PropertiesLauncher
Spring Boot’s org.springframework.boot.loader.PropertiesLauncher comes with a JVM argument to let you override the logical main-class called loader.main:
java -cp bootApp.jar -Dloader.main=org.khan.DemoApplication org.springframework.boot.loader.PropertiesLauncher
-Dspring.profiles.active
If you are using Spring profile then you need to set profile first
set SPRING_PROFILES_ACTIVE=default,test
or window run type envi and add
spring_profiles_active
default,test
--spring.config.location
Directory is specified then that is where the application.properties is searched for
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Just to add a simple solution without PropertiesLauncher or too much arguments.
1 - Build your standard executable springboot jar (my-spring-boot-app.jar)
2 - then run it without using the -jar option and using the JarLauncher class as the main class
java -cp "/path/to/jars/*:/path/to/app/my-spring-boot-app.jar" org.springframework.boot.loader.JarLauncher
(relative pathes are also perfectly valid)
that's all
The standard way to add dependencies in Spring Boot project is placing those Jar files into BOOT-INF/lib. This will result in copy that dependencies in the jar or war file generated and with the classpath.idx updated as well.
You can see the official documentation here
The accuracy literature says:
Application classes should be placed in a nested BOOT-INF/classes directory. Dependencies should be placed in a nested BOOT-INF/lib directory
I already do that with external Jar files and everything gone Ok.
One solution that worked for me was to insert the jar with the external classes into the MANIFEST.MF's Class-Path. That's because the -jar switch ignores the -classpath option and the CLASSPATH environment variable.
Procedure:
install the maven-jar-plugin into the POM;
add the lines:
<configuration>
<archive>
<manifestEntries>
<Class-Path>/my/external/jar/absolute/path.jar</Class-Path>
</manifestEntries>
</archive>
</configuration>
Build and run with java -jar myapp.jar. Its manifest will contain the line:
Class-Path: /my/external/jar/absolute/path.jar
This way the external jar will be searched at runtime and not at compile-time (it won't be copied in BOOT_INF/lib).
Sources:
post 1
post 2
Related
How to override Java resources when you run Spring Boot fat-jar?
I've created a Spring Boot far-jar that contains inside as resource a log4j.xml configuration file. Now when I run the fat-jar I'm trying to override it in this way
$ java -cp conf/ -jar target/myapp.jar
and I've put in the conf/ folder a new log4j.xml. But nothing, it continues to use the resource inside the jar.
If your goal is only to define your own log4j.xml configuration file, this could help:
java -Dlogging.config='/path/to/log4j2.xml' -jar target/myapp.jar
(this was mentioned already in How can I change the default location of log4j2.xml in Java Spring Boot? )
If you just want to add resources by classpath addition you could refer to
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-executable-jar-format.html#executable-jar-property-launcher-features
where I found loader.path :
loader.path can contain directories (which are scanned recursively for
jar and zip files), archive paths, a directory within an archive that
is scanned for jar files (for example, dependencies.jar!/lib), or
wildcard patterns (for the default JVM behavior). Archive paths can be
relative to loader.home or anywhere in the file system with a
jar:file: prefix.
I was going through spring-boot-maven-plugin documentation and came across a term auto executable jar.
Could someone please explain me what is an auto executable jar and how is it different then normal jar files and how they are auto executed?
spring-boot-maven-plugin documentation mentions the term but does not go further to explain it
repackage: create a jar or war file that is auto-executable. It can replace the regular artifact or can be attached to the build lifecycle with a separate classifier.
Could someone please explain me what is an auto executable jar
A fully executable jar can be executed like any other executable
binary or it can be registered with init.d or systemd. This makes it
very easy to install and manage Spring Boot applications in common
production environments.
So In conclusion is like any other executable when you use a executable jar
how is it different then normal jar files and how they are auto executed?
Well a java file you need to run with java -jar
From Spring Docs
The Maven build of a Springboot application first build your own application and pack it into a JAR file.
In the second stage (repackage) it will wrap that jar with all the jar files from the dependency tree into a new wrapper jar archive. It will also generate a Manifest file where is defined what's the application Main class is (also in the wrapper jar).
After mvn package you can also see 2 jar files in your target directory. The original file and the wrapped jar file.
You can start a Springboot application with a simple command like:
java -jar my-springboot-app.jar
I may suggest that auto executable means that you supplied main method so that it can be launched with java -jar options, otherwise it may be just a java library.
Here is a quote from https://docs.spring.io/spring-boot/docs/current/maven-plugin/repackage-mojo.html
Repackages existing JAR and WAR archives so that they can be executed from the command line using java -jar. With layout=NONE can also be used simply to package a JAR with nested dependencies (and no main class, so not executable).
Executable jar - the one that has main class declared in manifest and can be run with java -jar yourJarFile.jar command
Other jars - jars jars without delcared main calss. Can be anything - application, library, etc. Still can run application by providing fully.qualified.class.name as entry point like java -cp yourJarFile.jar my.bootstrap.BootstrapClass
Autoexecutable jars - never heard about it :)
I'm trying to get a maven managed project to run on the command line.
I have a set of dependencies in the pom.xml which are subsequently downloaded and installed in the ~/.m2/repository/. I've included the necessary config in my pom to add the classpath to the jar manifest.
Now the problem is i'm attempting to run the jar thus: java -jar project-SNAPSHOT.jar.
Java can't find the downloaded dependencies (i'm assuming because they are listed without paths in the manifest?) , but i'm not sure how best to get this running.
Options 1:
The jar created does not have the dependent jar files. So, you need to tell java the class-path where all the dependent jars are
java -cp /lcoation/of/dependency1.jar:/location/of/dependency2.jar:/location/of/dependency3.jar -jar project-SNAPSHOT.jar
Option 2:
The easier and much better solution is to use AppAssembler plugin. What it does it packages your jar in a directory structure that contains
dependent jars
the created jar
shell/windows scripts to execute it
have a look here http://www.mojohaus.org/appassembler/appassembler-maven-plugin/
Option 3:
If you do not want all the baggage and just wanted to have one jar-with-dependency
You may want to refer here How can I create an executable JAR with dependencies using Maven?
This will contain all the dependent jars within it.
Edit 1: For Option 1, Brad M mentioned that you can get a list of all your project's deps using the dependency plugin. dependency:build-classpath
mvn exec:java -Dexec.mainClass="com.vineetmanohar.module.Main" -Dexec.classpathScope=runtime
You can find more examples here: 3 ways to run Java main from Maven.
I have a jar file that is being created by Spring Boot. Application runs smoothly when run by command java -jar. I want to create an install anywhere launcher with this jar file.
What I have tried is to send the Spring Boot main class (PropertiesLauncher). The issue is that calling it like this won't load the nested jars inside my executable jar and also the loader.path doesn't seems to work.
Is there a way to call the executable jar like java -jar from the install anywhere launcher?
I was thinking that another option was to create an install anywhere launcher for a script file and inside have the java -jar call. So another question will be:
How do I create an install anywhere launcher for a script file?
'execute command' step will do the trick:
Use this command line:
java -jar <path.to.jar.file>
Use EXECUTE_STDOUT, EXECUTE_STDERR and EXECUTE_EXITCODE built-in variables to catch errors and parse the jar's execution result.
Important notes:
You'll have to make sure your jar includes all of the dependencies (or at least set the classpath in the command line);
To include the dependencies within your jar using eclipse you can:
Export your project as a 'runnable jar file' and select the
'Extract/Package required libraries into generated JAR' option/s
Use Maven to build the project with dependencies; the
maven-assembly-plugin is required.
The 'execute command' will work for batch/cmd/shell scripts as well, but you'll have to make sure the scripts are extracted to a local folder such as %TEMP% or /tmp before you can use them.
Goodluck
I am building an assembly in Maven for a command line utility. I can run it as an executable jar, but it fails because I need to load the config file externally. Assuming the following config, how would I run the jar?
Jar is in /opt/myapp/lib/myapp-assembly.jar
Config is in /etc/myapp/config/settings.xml
I'm loading the code from the classpath using ClassPathResource("/settings.xml");
Any help is appreciated!
I see two ways you could do it:
Launch the program using the jar as an archive rather than an executable jar, specifying the main class at run time. In other words, do java -classpath /opt/myapp/lib/myapp-assembly.jar:/etc/myapp/config [name of your main class].
Use the Class-Path field of the jar manifest file. Entries in it are directly added to the run time classpath, and there's nothing stopping you from specifying a filesystem directory rather than another jar file. So your manifest would contain: Class-Path: /etc/myapp/config/