Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

10 SpringBoot project use maven, How to reduce their jar size?

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.

  1. New a program as tool to calculate common artifactId between my projects, finally I got a artifactId list.

  2. New a maven module to package common dependencies, finally I got a lib document contains common jar files. I named it "common-lib".

  3. Change old project's pom file as follows:

  • add maven-jar-plugin to let my project load the common lib's classes
<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>
  • Change spring-boot-maven-plugin's configuration as fllows:
<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.

  1. Placed the myproject.jar and common-lib under the same directory
  • 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.

like image 517
Guevara Avatar asked Jan 01 '26 08:01

Guevara


1 Answers

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.

like image 157
JCompetence Avatar answered Jan 03 '26 11:01

JCompetence



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!