Spring native actual combat (experience the springboot application in 79 milliseconds)

Time:2021-10-23

Welcome to my GitHub

https://github.com/zq2599/blog_demos

Content: classification and summary of all original articles and supporting source code, involving Java, docker, kubernetes, Devops, etc;

About spring native

  • Spring official blogThe beta version of spring native was announced on March 11, 2021. Spring native can integrate spring applications with graalvmnative imageMedium;

  • Native image is a technology of graalvm. It can compile the bytecode of Java applications into executable files and statically link with the local library of JDK. There is no need for Java virtual machine when running applications. It has integrated memory management, thread scheduling and other capabilities. For more information, please refer to:https://www.graalvm.org/reference-manual/native-image/

  • This article focuses on actual combat, so I won’t spend too much time introducing the theory and advantages of spring native. Here is a brief summary of several important features:

  1. Application startup speed shall not exceed 100ms;
  2. The performance peak is reached upon startup (C1, C2 and other means are no longer available)
  3. Lower memory consumption at runtime;
  4. The docker image does not contain JDK (the required files have been extracted and put into the image). The size of the officially displayed image containing spring boot, spring MVC, Jackson and Tomcat is 50m;
  5. In order to achieve the above effect, the cost is that the construction time is longer;

What is spring native

Personal understanding: Spring native is a technical solution provided by spring for making native images, which involves the following key technologies:

  1. The spring ahead of time (AOT) plug-in performs AOT processing on spring applications, making the class lazy loading of traditional virtual machines no longer exist;
  2. When building the docker image, the spring boot Maven plugin uses the namedmikusa/graalvm-tinyAs a build tool, this tool is responsible for integrating the build results of the current project with graalvm, and finally making it into a native image;

Overview of this article

As a practical style article, the main content of this article is to develop the springboot application, build it into a native image, and then verify its function and effect. This paper consists of the following contents:

  1. environmental information
  2. Create a new Maven parent project named spring native tutorials, and uniformly configure the dependency libraries and plug-ins used in actual combat;
  3. Create a maven sub project named webmvc, which is a springboot application;
  4. Build webmvc as a native image, which is a docker image;
  5. Start the image in docker, verify whether it is available, and check relevant indicators;

environmental information

The environmental information related to the actual combat is as follows:

  1. Computer: MacBook Pro 13 inch 2018
  2. Operating system: MacOS Big Sur 11.2.3
  3. IDE:IntelliJ IDEA 2018.3.5 (Ultimate Edition)
  4. docker:20.10.5
  5. JDK:1.8.0_211
  6. maven:3.6.0
  7. springboot:2.5.0-SNAPSHOT
  8. spring-aot-maven-plugin:0.10.0-SNAPSHOT

Source download

  • The complete source code in this actual combat can be downloaded from GitHub. The address and link information are shown in the table below(https://github.com/zq2599/blog_demos):
name link remarks
Project Home https://github.com/zq2599/blog_demos The project is on the GitHub home page
Git warehouse address (HTTPS) https://github.com/zq2599/blog_demos.git The warehouse address of the source code of the project, HTTPS protocol
Git warehouse address (SSH) [email protected]:zq2599/blog_demos.git The project source code warehouse address, SSH protocol
  • There are multiple folders in this git project. The source code of this actual battle is inspring-native-tutorialsFolder, as shown in the red box below:

在这里插入图片描述

Create a new Maven parent project named spring native tutorials

  • The learning of spring native is not done by writing HelloWorld. Therefore, first create a parent project to provide unified dependency library and plug-in management for all applications in the future;

  • New namedspring-native-tutorialsThe content of pom.xml, the Maven parent project of, is as follows. Several points to note will be mentioned later:

4.0.0
    
        webmvc
    

    
        org.springframework.boot
        spring-boot-starter-parent
        2.5.0-SNAPSHOT
        
    

    com.bolingcavalry
    spring-native-tutorials
    1.0-SNAPSHOT

    pom

    
        1.8
        
        

        
        

        
        dmikusa/graalvm-tiny

        
        2020.0.2
    

    
    
        
            spring-release
            Spring release
            https://repo.spring.io/release
            
                false
            
        
        
            spring-milestone
            Spring milestone
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshot
            Spring Snapshots
            https://repo.spring.io/snapshot
            
                false
            
        
    

    
    
        
            spring-release
            Spring release
            https://repo.spring.io/release
            
                false
            
        
        
            spring-milestone
            Spring milestone
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshot
            Spring Snapshots
            https://repo.spring.io/snapshot
            
                false
            
        
    

    
    
        
            
                org.springframework.experimental
                spring-native
                0.10.0-SNAPSHOT
            
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud.version}
                pom
                import
            
        
    

    
    
        
            
                
                    org.springframework.boot
                    spring-boot-maven-plugin
                    
                        ${classifier}
                        
                            ${builder}
                            
                                true
                                ${native.build.args}
                            
                            
                            IF_NOT_PRESENT
                        
                    
                

                
                
                    org.springframework.experimental
                    spring-aot-maven-plugin
                    0.10.0-SNAPSHOT
                    
                        
                            test-generate
                            
                                test-generate
                            
                        
                        
                            generate
                            
                                generate
  • The above pom.xml has the following points to note:
  1. The configuration of plug-in warehouse, dependent library warehouse and dependent library version are centralized here;
  2. Configure spring AOT Maven plugin and spring boot Maven plugin, which will be used by the subproject;
  3. The spring boot Maven plugin is also used when making docker imagesdmikusa/graalvm-tinyImage, which is the real tool for building native image;

Create a maven sub project of springboot type

  • New namedwebmvcThe content of pom.xml is as follows. It can be seen that the content is very simple, that is, two plug-ins configured by the general dependency library and the parent project, one is responsible for executing AOT and the other is responsible for building image:
spring-native-tutorials
        com.bolingcavalry
        1.0-SNAPSHOT
    
    4.0.0
    webmvc
    
        
            org.springframework.experimental
            spring-native
        
        
            org.springframework.boot
            spring-boot-starter-web
            
                
                    org.apache.tomcat.embed
                    tomcat-embed-core
                
                
                    org.apache.tomcat.embed
                    tomcat-embed-websocket
                
            
        
        
            org.apache.tomcat.experimental
            tomcat-embed-programmatic
            ${tomcat.version}
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.experimental
                spring-aot-maven-plugin
                
                    true
                
            
            
                org.springframework.boot
                spring-boot-maven-plugin
  • The code is very simple. An ordinary springboot application with HTTP interface:
package com.bolingcavalry.webmvc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;

@SpringBootApplication
@RestController
public class WebmvcApplication {

	public static void main(String[] args) {
		SpringApplication.run(WebmvcApplication.class, args);
	}

	@ResponseStatus(HttpStatus.ACCEPTED)
	@GetMapping("/status")
	public String status() {
		return "status";
	}

	@GetMapping("/")
	public String hello() {
		return "1. Hello from Spring MVC and Tomcat, " + LocalDateTime.now();
	}
}
  • Now that the coding is complete, let’s build the docker image, enter the directory of pom.xml of the parent project, and execute the following command:
mvn clean -U -DskipTests spring-boot:build-image
  • After successful construction, the output information is as follows (only the last segment is intercepted due to space limitation), which takes 4 minutes and 25 seconds, during which the laptop fan rotates wildly:
...
[INFO] Successfully built image 'docker.io/library/webmvc:1.0-SNAPSHOT'
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for spring-native-tutorials 1.0-SNAPSHOT:
[INFO] 
[INFO] spring-native-tutorials ............................ SUCCESS [  1.786 s]
[INFO] webmvc ............................................. SUCCESS [04:19 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  04:25 min
[INFO] Finished at: 2021-05-22T16:36:44+08:00
[INFO] ------------------------------------------------------------------------
[WARNING] The requested profile "nexus" could not be activated because it does not exist.
  • implementdocker imagesCommand, as shown in the following figure, it can be seen that the image has been generated:

在这里插入图片描述

  • Looking at the image composition, it can be seen that each layer is small, with a total of more than 70 m:
(base) zhaoqindeMBP:~ zhaoqin$ docker history webmvc:1.0-SNAPSHOT
IMAGE          CREATED        CREATED BY   SIZE      COMMENT
b8ff54813ae0   41 years ago                69B
      41 years ago                452kB
      41 years ago                2.51MB
      41 years ago                57.2MB
      41 years ago                1.4MB
      41 years ago                268B
      41 years ago                17.3MB
  • The image is successfully built, and the basic functions can be verified;

verification

  • Execute the following command to create a temporary container (the container will be cleaned up after the console is completed):
docker run --rm -p 8080:8080 webmvc:1.0-SNAPSHOT
  • The console output is as follows. It starts in 79 milliseconds, which is really a blink of an eye:
(base) zhaoqindeMBP:~ zhaoqin$ docker run --rm -p 8080:8080 webmvc:1.0-SNAPSHOT
2021-05-22 09:34:57.578  INFO 1 --- [           main] o.s.nativex.NativeListener               : This application is bootstrapped with code generated with Spring AOT

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v2.5.0-SNAPSHOT)

2021-05-22 09:34:57.586  INFO 1 --- [           main] c.b.webmvc.WebmvcApplication             : Starting WebmvcApplication using Java 1.8.0_292 on 3529ec458896 with PID 1 (/workspace/com.bolingcavalry.webmvc.WebmvcApplication started by cnb in /workspace)
2021-05-22 09:34:57.586  INFO 1 --- [           main] c.b.webmvc.WebmvcApplication             : No active profile set, falling back to default profiles: default
2021-05-22 09:34:57.661  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
May 22, 2021 9:34:57 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-8080"]
May 22, 2021 9:34:57 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service [Tomcat]
May 22, 2021 9:34:57 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet engine: [Apache Tomcat/9.0.46]
May 22, 2021 9:34:57 AM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring embedded WebApplicationContext
2021-05-22 09:34:57.669  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 79 ms
May 22, 2021 9:34:57 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-nio-8080"]
2021-05-22 09:34:57.713  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-05-22 09:34:57.713  INFO 1 --- [           main] c.b.webmvc.WebmvcApplication             : Started WebmvcApplication in 0.178 seconds (JVM running for 0.19)
2021-05-22 09:34:57.713  INFO 1 --- [           main] o.s.b.a.ApplicationAvailabilityBean      : Application availability state LivenessState changed to CORRECT
2021-05-22 09:34:57.714  INFO 1 --- [           main] o.s.b.a.ApplicationAvailabilityBean      : Application availability state ReadinessState changed to ACCEPTING_TRAFFIC
  • The browser accesses the local 8080 port, as shown in the following figure. The basic functions of the application are normal:

在这里插入图片描述

  • Let’s look at the resource usage. The command isdocker statsAs can be seen below, only 30m memory is used:
CONTAINER ID   NAME               CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O     PIDS
6ce6c66fb4de   jovial_hertz       0.11%     30.69MiB / 3.844GiB   0.78%     1.49kB / 158B     4.31MB / 0B   18
  • I once put an image made by a traditional springboot application on hub.docker.combolingcavalry/hellojib:0.0.1-SNAPSHOTNow, compare it with the spring native image. The startup information is as follows. It takes 2036 milliseconds:
(base) zhaoqindeMacBook-Pro:~ zhaoqin$ docker run --rm -P docker.io/bolingcavalry/hellojib:0.0.1-SNAPSHOT

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.6.RELEASE)

2021-05-22 11:13:28.121  INFO 1 --- [           main] c.b.hellojib.HellojibApplication         : Starting HellojibApplication on ffb32e5b68b9 with PID 1 (/app/classes started by root in /)
2021-05-22 11:13:28.128  INFO 1 --- [           main] c.b.hellojib.HellojibApplication         : No active profile set, falling back to default profiles: default
2021-05-22 11:13:30.000  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-05-22 11:13:30.054  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-05-22 11:13:30.054  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.21]
2021-05-22 11:13:30.241  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-05-22 11:13:30.241  INFO 1 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2036 ms
2021-05-22 11:13:30.715  INFO 1 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-05-22 11:13:31.103  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-05-22 11:13:31.110  INFO 1 --- [           main] c.b.hellojib.HellojibApplication         : Started HellojibApplication in 3.618 seconds (JVM running for 4.297)
2021-05-22 11:13:48.866  INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-05-22 11:13:48.866  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-05-22 11:13:48.880  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 14 ms
  • Reusedocker statsCompared with memory, the container of traditional springboot applications consumes more than 300 megabytes of memory:
CONTAINER ID   NAME               CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O     PIDS
ffb32e5b68b9   eager_williamson   0.64%     356.3MiB / 3.844GiB   9.05%     3.46kB / 2.29kB   0B / 0B       31
6ce6c66fb4de   jovial_hertz       0.11%     30.69MiB / 3.844GiB   0.78%     1.49kB / 158B     4.31MB / 0B   18
  • To sum up, the advantages brought by spring native are obvious, butPlease note that: Spring native officially announced on March 11, 2021 is only a beta version,Please do not use it in production environment!!!

Failed to download Plug-in

During the actual operation, you often encounter the failure of downloading Maven plug-in or docker image. In addition to trying several times, you can also consider putting the project on GitHub and completing the image construction in the cloud with the help of GitHub action. For specific operations, please refer toMaking docker images with GitHub actions

No development, direct experience

  • I have uploaded the image to hub.docker.com. The full name isbolingcavalry/webmvc:1.0-SNAPSHOT, if you only want to experience the effect of native image, you can directly download the image for use;

You’re not alone. Xinchen’s original accompanies you all the way

  1. Java series
  2. Spring collection
  3. Docker series
  4. Kubernetes series
  5. Database + middleware series
  6. Devops series

Welcome to the official account: programmer Xin Chen

Wechat search “programmer Xinchen”, I’m Xinchen, looking forward to traveling with you in the Java World
https://github.com/zq2599/blog_demos