35

In an attempt to keep our microservices, developed in spring-boot to run on Cloud Foundry, smaller in footprint, we are looking for best approach to achieve the same.

Any inputs or pointers in this direction will be most welcomed.

It's surely the best that one always builds the application upwards starting from bare minimum dependencies, and the add any more only when required. Is there more of good practices to follow to further keep the application smaller in size?

Ashwin Gupta
  • 920
  • 1
  • 11
  • 17
  • Can you show us the dependencies you currently have ? Why do you think it could be smaller ? Surely, you have an idea of what could be done. What is the size of the generated artifact ? What are the jars insides and what are the biggest ? – alexbt Aug 31 '16 at 09:56
  • It's not about 'an' application in particular but spring (spring boot) applications in general. As compared to other languages like, Python, Ruby etc. the artefacts built in Java/Spring and Boot are quite big. So advise to know best practices to keep it smallest possible is sought. – Ashwin Gupta Aug 31 '16 at 10:42

2 Answers2

60

Below are some personal ideas on how to reach a smaller footprint with Spring Boot. Your question is too broad for these recommandations to be taken into account in any other context. I'm not entirely sure you want to follow these in most situation, it simply answers "how to achieve a smaller footprint".

(1) Only specify required dependencies

I wouldn't personally worry about it, but if the goal is to have a smaller footprint, you may avoid using starter-* dependencies. Only specify the dependencies you actually use.

Avoid this:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

In my sample project, the artifact produced with starter-* dependencies is ~25MB

Do this:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
</dependency>

In my sample project, the artifact produced without starter-* dependencies is ~15MB

(2) Exclude AutoConfigurations

Exclude the AutoConfiguration you don't need:

@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}

(3) Spring Boot properties

Disable as much as you can in the application.properties (while making sure it does not have a negative impact too):

spring.main.web-environment=false
spring.main.banner-mode=off
spring.jmx.enabled=false
server.error.whitelabel.enabled=false
server.jsp-servlet.registered=false
spring.freemarker.enabled=false
spring.groovy.template.enabled=false
spring.http.multipart.enabled=false
spring.mobile.sitepreference.enabled=false
spring.session.jdbc.initializer.enabled=false
spring.thymeleaf.cache=false
...

(4) Choose your embedded web container wisely

If launching spring boot with an embedded web container, you may choose a different one:

(5) Spring's recommandations

  • Memory: java -Xmx32m -Xss256k -jar target/demo-0.0.1-SNAPSHOT.jar
  • Number of threads: server.tomcat.max-threads: 4
  • source: spring-boot-memory-performance

(6) See also:

alexbt
  • 16,415
  • 6
  • 78
  • 87
  • Great reply Alex. Thanks. This kind of replies is what I've been looking for. I will like to wait for couple of more days to let more people reply and add to it before accepting your reply as the best answer. – Ashwin Gupta Sep 01 '16 at 03:56
  • Couple of questions though on point #1 of Avoid using `starter-*` dependencies: 1) Will not that make my application a less of Spring-Boot application while taking dependencies directly from springframework? & 2) That gives a developer the headache to manage versions for each of these dependencies, otherwise managed by Spring-Boot frameworrk. – Ashwin Gupta Sep 01 '16 at 04:56
  • 1
    the starter is simply an aggregator of dependencies. So importing starter-data-jpa, infact imports spring-aop, aspectjweaver, tomcat-jdbc, tomcat-juli... You may end up with a couple less dependencies if you import what you need yourself. My post wasn't clear on this: these are recommandations to lower the foot print, but I personally wouldn't worry about it and I much prefer to use starter-*. – alexbt Sep 01 '16 at 10:19
  • see http://stackoverflow.com/questions/28273543/what-are-spring-boot-starter-jars – alexbt Sep 01 '16 at 10:23
  • I agree, the loss of flexibility when one do NOT use starter-* dependencies is too much as compared to using starter's. Also `disabling AutoConfigurations you don't need` and `disable all unused Spring Boot Properties` is not an easy task to achieve, given there is incredibly huge list to go through and decide upon for each of those. That makes is almost an impractical to be perfect. – Ashwin Gupta Sep 01 '16 at 11:56
  • I would still accept your reply as an answer as this provides the way to reduce the artefact size and memory footprint even though at a cost. Thanks for it. – Ashwin Gupta Sep 01 '16 at 11:58
0

Assuming you want to:

  1. quickly bootstrap a lightweight SpringBoot app
  2. ignore the classpath containing autoconfiguration classes you care nothing about

use truncated version of @SpringBootApplication with autoconfiguration disabled, i.e.:

@SpringBootConfiguration // and not @SpringBootApplication
class LightweightTestApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(LightweightTestApplication.class)
                .web(WebApplicationType.NONE) // even disable WEB features
                .run(args);
    }
}

Then include configurations on demand as you like, e.g. leverage @ComponentScan or @Import. Example:

@SpringBootConfiguration
@ComponentScan(basePackageClasses = { 
    ...AutoConfiguration.class,
    ...AutoConfiguration.class,
})
class LightweightTestApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(LightweightTestApplication.class)
                .web(WebApplicationType.NONE)
                .run(args);
    }
}

The accepted answer gives great tips on dependencies and should be preferred.

Use my hints when you care less about /lib dir and more about limiting Spring ambition, so for dirty development, WIP, PoC.

This approach is also powerful in unit/integration testing based on Spring context that should never grow unnoticeably as a side effect of an added dependency for an unrelated feature

ptomaszek
  • 123
  • 1
  • 8