-
Linux or Windows environment
- Native Images creation are not supported on Mac OS yet
- You can use Docker contianers on Mac, if you know what you are doing
docker container run --name graalvm-workspace --rm -it -v $PWD:/app yogendra/graalvm-workspace:latest-
There is no git on this image, you can use curl to download the repo as an archive instead
curl -L https://github.com/yogendra/spring-native-workshop/archive/main.tar.gz -o spring-native-workshop.tgz tar -xzvf spring-native-workshop.tar.gz mv spring-native-workshop-main spring-native-workshop cd spring-native-workshop
-
-
> java -version openjdk version "11.0.10" 2021-01-19 OpenJDK Runtime Environment GraalVM CE 21.0.0.2 (build 11.0.10+8-jvmci-21.0-b06) OpenJDK 64-Bit Server VM GraalVM CE 21.0.0.2 (build 11.0.10+8-jvmci-21.0-b06, mixed mode, sharing) -
JAVA_HOME point to GraalVM
- MacOS: export JAVA_HOME=/path/to/graalvm/Contents/Home
- Windows: set JAVA_HOME=c:\path\to\graalvm
- Linux: export JAVA_HOME=/path/to/graalvm
-
PATH variable contains GraalVM bin folder
- MacOS: export PATH=$JAVA_HOME/bin:$PATH
- Windows: set JAVA_HOME=%JAVA_HOME%\bin;%PATH$
- Linux: export JAVA_HOME=$JAVA_HOME/bin:$PATH
-
> gu install native-image -
Clone this repository
git clone http://github.com/yogendra/spring-native-workshop.git spring-native-workshop -
Apache Maven 3.x
Directory: examples/CountUppercase
-
Lets compile it first
javac -d out CountUppercase.java -
This produced
CountUppercase.classin same directory. We can run this using following command.java -cp out CountUppercaseOutput:
1 (380 ms) 2 (288 ms) 3 (243 ms) 4 (260 ms) 5 (285 ms) 6 (238 ms) 7 (235 ms) 8 (240 ms) 9 (253 ms) total: 69999993 (2655 ms) -
You can see the compilation time using follwing command
java -cp out -Dgraal.PrintCompilation=true CountUppercaseOutput:
[Use -Dgraal.LogFile=<path> to redirect Graal log output to a file.] HotSpotCompilation-177 Ljava/lang/Object; <init> ()V | 11405us 2B bytecodes 91B codesize HotSpotCompilation-260 Ljava/util/stream/AbstractPipeline; wrapSink (Ljava/util/stream/Sink;)Ljava/util/stream/Sink; | 12779us 204B bytecodes 542B codesize HotSpotCompilation-244 Ljava/lang/StringLatin1$CharsSpliterator; forEachRemaining (Ljava/util/function/IntConsumer;)V | 6242us 886B bytecodes 914B codesize HotSpotCompilation-271 Ljava/util/stream/IntPipeline$9; opWrapSink (ILjava/util/stream/Sink;)Ljava/util/stream/Sink; | 1775us 102B bytecodes 338B codesize HotSpotCompilation-261 Ljava/util/stream/AbstractPipeline; evaluate (Ljava/util/stream/TerminalOp;)Ljava/lang/Object; | 20356us 2597B bytecodes 2450B codesize HotSpotCompilation-182 Ljava/lang/CharacterData; of (I)Ljava/lang/CharacterData; | 707us 240B bytecodes 102B codesize HotSpotCompilation-191 LCountUppercase$$Lambda$14/603742814; test (I)Z | 1803us 666B bytecodes 242B codesize HotSpotCompilation-192 Ljava/util/stream/IntPipeline$9$1; accept (I)V | 2944us 742B bytecodes 498B codesize HotSpotCompilation-193 Ljava/lang/CharacterDataLatin1; isUpperCase (I)Z | 1031us 62B bytecodes 185B codesize HotSpotCompilation-195 Ljava/lang/CharacterDataLatin1; isOtherUppercase (I)Z | 1045us 58B bytecodes 198B codesize HotSpotCompilation-178 Ljava/util/Objects; requireNonNull (Ljava/lang/Object;)Ljava/lang/Object; | 580us 28B bytecodes 82B codesize HotSpotCompilation-196 Ljava/util/stream/ReduceOps$CountingSink$OfInt; accept (I)V | 390us 22B bytecodes 108B codesize HotSpotCompilation-226 Ljava/util/stream/AbstractPipeline; isParallel ()Z | 491us 16B bytecodes 150B codesize HotSpotCompilation-183 Ljava/lang/String; isLatin1 ()Z | 669us 38B bytecodes 154B codesize HotSpotCompilation-250 Ljava/lang/invoke/Invokers$Holder; linkToTargetMethod (Ljava/lang/Object;)Ljava/lang/Object; | 1330us 16B bytecodes 140B codesize HotSpotCompilation-251 Ljava/lang/invoke/DirectMethodHandle$Holder; getObject (Ljava/lang/Object;)Ljava/lang/Object; | 10385us 68B bytecodes 442B codesize HotSpotCompilation-252 Ljava/util/stream/AbstractPipeline; <init> (Ljava/util/stream/AbstractPipeline;I)V | 4239us 260B bytecodes 1010B codesize HotSpotCompilation-253 Ljava/util/stream/StreamOpFlag; fromCharacteristics (Ljava/util/Spliterator;)I | 1319us 84B bytecodes 157B codesize HotSpotCompilation-254 Ljava/util/stream/AbstractPipeline; <init> (Ljava/util/Spliterator;IZ)V | 2796us 115B bytecodes 700B codesize HotSpotCompilation-266 Ljava/lang/String; chars ()Ljava/util/stream/IntStream; | 6045us 435B bytecodes 690B codesize HotSpotCompilation-268 Ljava/util/stream/IntPipeline; filter (Ljava/util/function/IntPredicate;)Ljava/util/stream/IntStream; | 4016us 177B bytecodes 374B codesize HotSpotOSRCompilation-279 LCountUppercase; main ([Ljava/lang/String;)V (OSR@61) | 25972us 1780B bytecodes 4658B codesize HotSpotCompilation-269 Ljava/util/stream/IntPipeline; count ()J | 2399us 66B bytecodes 402B codesize HotSpotCompilation-267 Ljava/lang/StringLatin1$CharsSpliterator; <init> ([BIII)V | 1880us 72B bytecodes 352B codesize HotSpotCompilation-243 Ljava/util/stream/Sink; end ()V | 285us 2B bytecodes 91B codesize HotSpotCompilation-262 Ljava/util/stream/AbstractPipeline; sourceSpliterator (I)Ljava/util/Spliterator; | 1954us 607B bytecodes 370B codesize HotSpotCompilation-263 Ljava/util/stream/AbstractPipeline; wrapAndCopyInto (Ljava/util/stream/Sink;Ljava/util/Spliterator;)Ljava/util/stream/Sink; | 10653us 1576B bytecodes 1426B codesize HotSpotCompilation-264 Ljava/util/stream/AbstractPipeline; copyInto (Ljava/util/stream/Sink;Ljava/util/Spliterator;)V | 7187us 1308B bytecodes 1010B codesize HotSpotCompilation-265 Ljava/util/Spliterator; getExactSizeIfKnown ()J | 1029us 82B bytecodes 198B codesize HotSpotCompilation-245 Ljava/util/stream/ReduceOps$9; getOpFlags ()I | 255us 8B bytecodes 96B codesize HotSpotCompilation-246 Ljava/lang/StringLatin1$CharsSpliterator; estimateSize ()J | 359us 22B bytecodes 102B codesize HotSpotCompilation-247 Ljava/util/stream/ReduceOps$CountingSink; begin (J)V | 314us 12B bytecodes 102B codesize HotSpotCompilation-270 Ljava/util/stream/ReduceOps$9; evaluateSequential (Ljava/util/stream/PipelineHelper;Ljava/util/Spliterator;)Ljava/lang/Object; | 15755us 1786B bytecodes 2098B codesize HotSpotCompilation-272 Ljava/util/stream/IntPipeline$9$1; begin (J)V | 1139us 38B bytecodes 213B codesize HotSpotCompilation-273 Ljava/util/Spliterator$OfInt; forEachRemaining (Ljava/util/function/Consumer;)V | 7528us 992B bytecodes 951B codesize HotSpotCompilation-274 Ljava/util/stream/Sink$ChainedInt; end ()V | 748us 22B bytecodes 210B codesize HotSpotCompilation-275 Ljava/util/stream/ReduceOps$CountingSink$OfInt; get ()Ljava/lang/Object; | 1174us 18B bytecodes 358B codesize HotSpotCompilation-276 Ljava/lang/Long; valueOf (J)Ljava/lang/Long; | 1038us 80B bytecodes 151B codesize HotSpotCompilation-289 Ljava/lang/String; hashCode ()I | 1284us 136B bytecodes 294B codesize HotSpotCompilation-307 Ljava/lang/String; charAt (I)C | 1316us 144B bytecodes 255B codesize HotSpotCompilation-309 Ljava/lang/StringLatin1; equals ([B[B)Z | 1671us 72B bytecodes 306B codesize 1 (333 ms) HotSpotCompilation-317 Ljava/util/HashMap; resize ()[Ljava/util/HashMap$Node; | 16879us 712B bytecodes 3698B codesize HotSpotCompilation-318 Ljava/lang/StringLatin1; hashCode ([B)I | 3970us 84B bytecodes 469B codesize HotSpotOSRCompilation-334 LCountUppercase; main ([Ljava/lang/String;)V (OSR@61) | 29429us 1787B bytecodes 7474B codesize HotSpotCompilation-319 Ljava/util/HashMap; putVal (ILjava/lang/Object;Ljava/lang/Object;ZZ)Ljava/lang/Object; | 17101us 952B bytecodes 3730B codesize 2 (141 ms) 3 (87 ms) 4 (145 ms) 5 (89 ms) 6 (87 ms) 7 (88 ms) 8 (126 ms) 9 (84 ms) total: 69999993 (1263 ms) -
Now lets just run the same code without GraavVM compilation, just the regular JVM
java java -cp out -XX:-UseJVMCICompiler CountUppercaseOutput:
1 (240 ms) 2 (113 ms) 3 (80 ms) 4 (182 ms) 5 (85 ms) 6 (80 ms) 7 (78 ms) 8 (74 ms) 9 (145 ms) total: 69999993 (1162 ms) -
Make a native binary (Windows and Linux only)
native-image --static -cp out CountUppercase out/count-uppercaseOutput:
-
Run native image
out/count-uppercaseOutput:
Directory: examples/Blender
-
Compile
Blender.javajavac -d out Blender.java -
Run
Blenderwith GraalVMjava -cp out BlenderOutput:
949 ms 912 ms 907 ms 912 ms 945 ms 963 ms 967 ms 997 ms 1309 ms 971 ms -
Run
Blenderwithout GraalVMjava -cp out -XX:-UseJVMCICompiler BlenderOutput:
1528 ms 1190 ms 1193 ms 1208 ms 1181 ms 1381 ms 1191 ms 1339 ms 1287 ms 1159 ms -
Make a native binary (Windows and Linux only)
native-image --static -cp out Blender out/blenderOutput:
-
Run native image
out/blenderOutput:
Directory: examples/HelloWorld
Lets build a docker image with a native binary. Nothing big, just a simple "Hellow, World!"
make demo
Source: Spring Native Beta Announcement Source: Spring Natice Introduction
-
Create a simple project using spring initializer. Use any one of the options below
- Use the project in this repo
examples/springnative- Go to project directory
cd examples/springnative
- Go to project directory
- Prepopulated GUI
- Click here to bring up pre-populated form.
- Client Generate to download the zipped project code.
- Save the extract archive
springnative.zipinto theexamplesdirectory - Go to project directory
cd examples/springnative
- Use the GUI and generate the project
-
Go to Spring Initializr
-
Fill the form as per below screen shot
- Project: Maven
- Spring Boot: 2.4.3
- Project Metadata
- Group: me.yogendra.examples
- Artifact: springnative
- Name: springnative
- Description: Demo for Spring Native
- Package name: me.yogendra.examples.springnative
- Packaging: Jar
- Java: 11
- Dependencies:
- Spring Native [Experimental] (Developer Tools)
-
Client Generate to download the zipped project code.
-
Save the extract archive
springnative.zipinto theexamplesdirectory -
Go to project directory
cd examples/springnative
-
- Command Line (My Favorite)
-
Create a project directory
mkdir -p examples/springnative -
Go to project directory
cd examples/springnative -
In the
examples/springnativedirectory, execute following command to download the preconfigured project as a zip filecurl https://start.spring.io/starter.zip \ -d type=maven-project \ -d language=java \ -d platformVersion=2.4.3.RELEASE \ -d packaging=jar \ -d jvmVersion=11 \ -d groupId=me.yogendra.examples \ -d artifactId=springnative \ -d name=springnative \ -d description=Demo%20for%20Spring%20Native \ -d packageName=me.yogendra.examples.springnative \ -d dependencies=native \ -o springnative.zip -
Unzip the
springnative.zipunzip springnative.zip
-
- Use the project in this repo
-
Lets look at the
spring-boot:helptarget in Maven./mvnw spring-boot:helpOutput:
[INFO] Scanning for projects... [INFO] [INFO] -----------------< me.yogendra.examples:springnative >------------------ [INFO] Building springnative 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- spring-boot-maven-plugin:2.4.3:help (default-cli) @ springnative --- [INFO] Spring Boot Maven Plugin 2.4.3 This plugin has 7 goals: spring-boot:build-image Package an application into a OCI image using a buildpack. spring-boot:build-info Generate a build-info.properties file based the content of the current MavenProject. spring-boot:help Display help information on spring-boot-maven-plugin. Call mvn spring-boot:help -Ddetail=true -Dgoal=<goal-name> to display parameter details. spring-boot:repackage Repackage existing JAR and WAR archives so that they can be executed from the command line using java -jar. With layout=NONE can also be used simply to package a JAR with nested dependencies (and no main class, so not executable). spring-boot:run Run an application in place. spring-boot:start Start a spring application. Contrary to the run goal, this does not block and allows other goals to operate on the application. This goal is typically used in integration test scenario where the application is started before a test suite and stopped after. spring-boot:stop Stop an application that has been started by the 'start' goal. Typically invoked once a test suite has completed. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.428 s [INFO] Finished at: 2021-03-18T18:07:48+08:00 [INFO] ------------------------------------------------------------------------Build the project and run it.
./mvnw clean install -
So you can see the
spring-boot:build-image. This builds a docker image with native binary. Lest use that./mvnw spring-boot:build-imageOutput:
... [INFO] Successfully built image 'docker.io/library/springnative:0.0.1-SNAPSHOT' [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 46.317 s [INFO] Finished at: 2021-03-18T18:26:41+08:00 [INFO] ------------------------------------------------------------------------ -
Examine the image
dive docker.io/library/springnative:0.0.1-SNAPSHOT -
Run image
docker run --rm --name springnative-test docker.io/library/springnative:0.0.1-SNAPSHOT
If you are on Mac, create a Linux VM (preferrably Ubuntu) and use that to run and examine sample. Mac OS native binary generation does not work yet. And remember your target environment will be linux in a container so it just makes sense to compile in a Linux environment as such.
-
Checkout Spring Native repository
git clone https://github.com/spring-projects-experimental/spring-native.git -
Change to the directory
cd spring-native
-
Change to Petclinic App
cd samples/petclinic-jpa -
Lets run one of them - Pet Clinic
cd samples/petclinic-jpa -
Build it!
For detailed instructions follow documentation.
I am using Docker machine to create a Linux VM.
-
Create a docker machine VM
docker-machine create --driver amazonec2 \ --amazonec2-zone "a" \ --amazonec2-region ap-southeast-1 \ --amazonec2-open-port 8080 \ --amazonec2-open-port 8443 \ --amazonec2-open-port 80 \ --amazonec2-open-port 443 \ --amazonec2-instance-type "t3.2xlarge" \ --amazonec2-root-size 100 \ spring-native -
SSH to the machine
docker-machine ssh spring-native -
Add user to docker group
sudo usermod -aG docker $USER -
Install docker-compose
sudo apt-get install docker-compose -
Install graalvm and maven
curl -L https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0.2/graalvm-ce-java11-linux-amd64-21.0.0.2.tar.gz -o graalvm.tgz tar -xzvf graalvm.tgz mv graalvm-ce-java11-21.0.0.2 $HOME/graalvm $HOME/graalvm/bin/gu install native-image curl -L https://apachemirror.sg.wuchna.com/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz -o maven.tgz tar -xzvf maven.tgz mv apache-maven-3.6.3 maven echo export PATH=\$HOME/graalvm/bin:\$HOME/maven/bin:\$PATH >> ~/.bashrc echo export JAVA_HOME=\$HOME/graalvm >> ~/.bashrc export PATH=$HOME/graalvm/bin:$HOME/maven/bin:$PATH export JAVA_HOME=$HOME/graalvm -
Reboot the machine to pickup user group changes
sudo reboot -
Verify GraalVM Setup
java -version -
Verify docker setup
docker ps
- Workspace enhacenment
- Add a browser based gui
- Add git
- Enhance sample organization
