24

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?

1

7 Answers 7

15

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

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you, this worked for us. Remember to use ":" as separator in the classpath if you are on un*x.
This solution supports reading config files from the classpath at startup time, so this is a win for my little spring-boot app. This should be the accepted answer.
Remember to use the fully qualified name of the class for -Dloader.main
14

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.

8 Comments

I have actually tried that. See my original question. It is not working exactly as -classpath. It loads the jar files, but not the ini files.
@user1670498, sorry I overlooked that. Please see my answer for new details.
Actually, it works for non jar files, but not jar files. So my app can read any ini files in /home/sleeper/thirdparty/lib/ from the classpath, but it cannot load any jar files from /home/sleeper/thirdparty/lib/.
After a lot of researching, seems "Class-Path: /home/sleeper/thirdparty/lib/" will not load any jar files under the folder. To reference jar file, we would need to explicitily reference each individual jar, something like "Class-Path: /home/sleeper/thirdparty/lib/abc.jar /home/sleeper/thirdparty/lib/def.jar".
I actually read that blog, and I have the class-path ends in "/". I think what the blog says is, it won't load the jar files in the directory, but it will load .class files in the directory.
|
8

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.

Comments

6
 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

-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

Comments

3

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

3 Comments

This worked also with org.springframework.batch.core.launch.support.CommandLineJobRunner as the declared main class in the manifest.
Didn't work for me. Got this exception. "Error: Could not find or load main class org.springframework.boot.loader.JarLauncher Caused by: java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher"
JarLauncher class has moved to org.springframework.boot.loader.launch.JarLauncher since 3.2
2

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:

  1. install the maven-jar-plugin into the POM;
  2. 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

Comments

1

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.