our project has about 10 SpingBoot module, we use maven to manage dependencies. 10 jar size about 2G. recently we need to reduce the jar size convenient for our customer deploy.
I got an idea, extract common jar(no very often change), such as spring-.jar, spring-boot-.jar, jodd*.jar, elasticsearch etc. As long as >= 2 project use one same dependence, the one we called "common jar".
If u know some useful solutions, please tell me.
I have tried under method, but met some troubles.
New a program as tool to calculate common artifactId between my projects, finally I got a artifactId list.
New a maven module to package common dependencies, finally I got a lib document contains common jar files. I named it "common-lib".
Change old project's pom file as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.xx.MyManagerApplication</mainClass>
<useUniqueVersions>false</useUniqueVersions>
<addClasspath>true</addClasspath>
<!--classpathPrefix let Manifest.MF's Class-Path add the 'common-lib' as prefix-->
<classpathPrefix>common-lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.xx.MyManagerApplication</mainClass>
<layout>ZIP</layout>
<excludeArtifactIds>
spring-webmvc,
spring-web,
spring-tx,
spring-security-rsa,
spring-security-crypto,
spring-jdbc,
spring-jcl,
spring-expression,
spring-core,
spring-context,
spring-cloud-starter-zipkin,
...ellipsis
</excludeArtifactIds>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
finally my project's jar lib only contains none common-lib. and the jar size reduce to 900K(105M in the past). It greatly reduce the jar size.
- common-lib
- many jars...
- myproject.jar
Then start up my project
java -Dspring.profiles.active=dev -Dspring.config.location=application.yml -jar my-project.jar
However it did not work as I dreamd. instead with a error message show in the console
[2020-12-01 15:54:19.252+0800]-[foundation-manager]-[1;31m[ERROR][0;39m-[]-[8340:main] o.s.boot.SpringApplication 837 : Application run failed
java.lang.NoClassDefFoundError: groovy/lang/GroovyObject
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.springframework.boot.BeanDefinitionLoader.<init>(BeanDefinitionLoader.java:84)
at org.springframework.boot.SpringApplication.createBeanDefinitionLoader(SpringApplication.java:745)
at org.springframework.boot.SpringApplication.load(SpringApplication.java:685)
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:381)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:305)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:137)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.bootstrapServiceContext(BootstrapApplicationListener.java:208)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:104)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:70)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:74)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:338)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:297)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1242)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1230)
at com.yealink.foundation.manager.app.FoundationManagerApplication.main(FoundationManagerApplication.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
at org.springframework.boot.loader.PropertiesLauncher.main(PropertiesLauncher.java:593)
Caused by: java.lang.ClassNotFoundException: groovy.lang.GroovyObject
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 40 common frames omitted
groovy's lib is not common-lib, it exist in the project's jar. the reason is the step 2 I changed the Manifest.MF file so jvm find the groovy's lib in the common-lib/groovy.xxx.jar ?
If u know some useful solutions, please tell me.
I had done something similar to your setup, but in my case it was for optimizing Docker push.
My spring-boot-maven-plugin is different though:
See if the below helps you:
<!-- This plugin copies different external dependencies into separate folders
that are later used to build an optimized Docker image -->
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-external-project-dependencies</id>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<excludeGroupIds>com.susan</excludeGroupIds>
<outputDirectory>${project.build.directory}/external-dependencies</outputDirectory>
</configuration>
</execution>
<execution>
<id>copy-hello-cloud-platform-dependencies</id>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<includeGroupIds>com.susan.hello.cloud-platform</includeGroupIds>
<outputDirectory>${project.build.directory}/cloud-dependencies</outputDirectory>
</configuration>
</execution>
<execution>
<id>copy-susan-project-dependencies</id>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<includeGroupIds>com.susan.ca.cc</includeGroupIds>
<outputDirectory>${project.build.directory}/susan-dependencies</outputDirectory>
</configuration>
</execution>
<execution>
<id>submodule-dependencies</id>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<includeGroupIds>com.susan</includeGroupIds>
<excludeGroupIds>com.susan.ca.cc,com.susan.hello.cloud-platform</excludeGroupIds>
<outputDirectory>${project.build.directory}/submodule-dependencies</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
</execution>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<skip>true</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.susan.hello.whee.HelloApplication</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
COPY /susan/target/external-dependencies /lib
COPY /susan/target/hello-dependencies /lib
COPY /susan/target/cloud-dependencies /lib
COPY /susan/target/submodule-dependencies /lib
The app.jar is outside of the /lib
java - jar app.jar
It all looks the same as you have done, the only thing I can think of is spring-boot-maven-plugin setup.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With