This project shows how to build "micro" applications with Spring and Spring Boot - the smallest, functional units, with the fewest dependencies and fastest start times
Build the jar:
$ ./mvnw clean install
Run it
$ java -jar target/micro-0.0.1-SNAPSHOT.jar
...
2018-05-23 10:03:41.776 [main] INFO com.example.demo.DemoApplication - Started DemoApplication in 1.885 seconds (JVM running for 3.769)
...
The default app is relatively full-bodied - it uses Spring Boot and auto-configuration.
You can run the smaller apps using command line flags:
$ java -jar target/micro-0.0.1-SNAPSHOT.jar --thin.main=com.example.mini.MiniApplication
...
May 23, 2018 10:05:41 AM reactor.util.Loggers$Slf4JLogger info
INFO: Started HttpServer on /127.0.0.1:8080
The main class could be one of
Main |
Description |
|
com.example.demo.DemoApplication |
(The default). Spring Boot with Webflux and full autoconfiguration |
|
com.example.boot.BootApplication |
Spring Boot with Webflux and |
|
com.example.func.BuncApplication |
Spring Boot with Webflux and |
|
com.example.mini.MiniApplication |
Raw Spring, no autoconfiguration, but using |
|
com.example.micro.MicroApplication |
Raw Spring with no |
The thin.profile
could be empty (the default) for just spring-boot-starter-webflux
dependencies, or you can try jack
for a more "normal" set of dependencies, e.g. with hibernate-validator
, jackson
, and logback
. Other choices add more dependencies (e.g. actr
for spring-boot-starter-actuator
). You will need the "jack" profile to use actuators, so --thin.profile=actr,jack
.
The apps are already systematically benchmarked here with regular JVMs: https://github.com/dsyer/spring-boot-startup-bench/blob/master/flux/README.adoc. The point of this project is just to extract them out of the JMH benchmarks, and make them easily executable as standalone apps. In the benchmarks, the "jack" profile is the default, and "jlog" is the faster reduced set of dependencies.
class method sample beans classes heap memory median mean range
MainBenchmark main empt 24.000 3230.000 5.103 38.769 0.546 0.555 0.018
MainBenchmark main jlog 80.000 3598.000 6.141 43.006 0.667 0.679 0.019
MainBenchmark main demo 93.000 4365.000 8.024 49.564 0.766 0.773 0.011
MainBenchmark main actr 174.000 5172.000 8.538 54.216 0.902 0.911 0.020
MainBenchmark main jdbc 131.000 5261.000 9.174 55.252 0.883 0.902 0.031
MainBenchmark main actj 214.000 5510.000 9.007 56.571 0.995 1.021 0.065
class method sample beans classes heap memory median mean range
MiniBenchmark boot jlog 28.000 3336.000 7.082 41.949 0.588 0.597 0.014
MiniBenchmark boot demo 28.000 4012.000 6.508 45.566 0.703 0.710 0.011
MiniBenchmark first jlog 2.000 2176.000 6.556 38.574 0.416 0.418 0.004
MiniBenchmark first demo 2.000 2913.000 5.647 42.091 0.515 0.523 0.008
MiniBenchmark micro jlog 2.000 2176.000 4.608 32.886 0.336 0.345 0.013
MiniBenchmark micro demo 2.000 2913.000 7.318 40.454 0.438 0.451 0.016
MiniBenchmark mini jlog 27.000 3059.000 5.487 38.953 0.534 0.545 0.018
MiniBenchmark mini demo 27.000 3732.000 5.969 43.726 0.631 0.636 0.007
All the apps are compilable to a native binary image using the Graal tools once you have Andy’s Spring Boot Graal Feature library - just clone it and mvn install
it.
Download GraalVM and install it (add the bin dir to you path and set the JAVA_HOME
to point to GraalVM). You can also use sdkman to download it. You will need GraalVM 19.0.
Compute the classpath using the graal
profile so that we can work around some limitations of the Graal Features library:
$ CP=`java -jar target/micro-0.0.1-SNAPSHOT.jar --thin.classpath --thin.profile=graal`
Then build an image:
$ native-image -Dio.netty.noUnsafe=true --no-server -H:Name=target/micro -H:+ReportExceptionStackTraces --no-fallback --allow-incomplete-classpath --report-unsupported-elements-at-runtime -cp target/classes:$CP:${HOME}/.m2/repository/org/springframework/spring-boot-graal-feature/0.5.0.BUILD-SNAPSHOT/spring-boot-graal-feature-0.5.0.BUILD-SNAPSHOT.jar com.example.micro.MicroApplication
Then run it:
$ ./target/micro
Started HttpServer: 2ms
Excellent!
You can do the same with all the applications in this project, including DemoApplication
(full Spring Boot):
$ native-image -Dio.netty.noUnsafe=true --no-server -H:Name=target/demo -H:+ReportExceptionStackTraces --no-fallback --allow-incomplete-classpath --report-unsupported-elements-at-runtime -cp target/classes:$CP:${HOME}/.m2/repository/org/springframework/spring-boot-graal-feature/0.5.0.BUILD-SNAPSHOT/spring-boot-graal-feature-0.5.0.BUILD-SNAPSHOT.jar com.example.demo.DemoApplication
$ ./target/demo
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::
Aug 07, 2018 11:25:13 AM org.springframework.boot.StartupInfoLogger logStarting
INFO: Starting application on tower with PID 11253 (started by dsyer in /home/dsyer/dev/demo/workspace/micro)
Aug 07, 2018 11:25:13 AM org.springframework.boot.SpringApplication logStartupProfileInfo
INFO: No active profile set, falling back to default profiles: default
Aug 07, 2018 11:25:13 AM org.springframework.boot.web.embedded.netty.NettyWebServer start
INFO: Netty started on port(s): 8080
Aug 07, 2018 11:25:13 AM org.springframework.boot.StartupInfoLogger logStarted
INFO: Started application in 0.036 seconds (JVM running for 0.04)
Benchmark app started
Started HttpServer: 40ms
Note that whenever @Configuration
is used, including in meta annotations like @SpringBootApplication
, it must have the proxyBeanMethods = false
flag set. CGLib is not friendly with GraalVM native images.