เนทีฟในช่วงฤดูใบไม้ผลิบน Google Cloud

เนทีฟในช่วงฤดูใบไม้ผลิบน Google Cloud

เกี่ยวกับ Codelab นี้

subjectอัปเดตล่าสุดเมื่อ มี.ค. 17, 2022
account_circleเขียนโดย Aaron Wanjala

1 ภาพรวม

ใน Codelab นี้ เราจะเรียนรู้เกี่ยวกับโปรเจ็กต์ Spring Native, การสร้างแอปที่ใช้แอป และทำให้แอปใช้งานได้ใน Google Cloud

เราจะดูคอมโพเนนต์ของโปรเจ็กต์ ประวัติล่าสุดของโปรเจ็กต์ กรณีการใช้งานบางส่วน และขั้นตอนที่จำเป็นในการใช้โปรเจ็กต์ในโปรเจ็กต์ของคุณ

ปัจจุบันโปรเจ็กต์เนทีฟในฤดูใบไม้ผลิอยู่ในขั้นทดลอง ดังนั้นจึงต้องมีการกำหนดค่าเฉพาะบางอย่างเพื่อเริ่มต้นใช้งาน อย่างไรก็ตาม ตามที่ได้ประกาศไปในงาน SpringOne 2021 ว่า Spring Native จะผสานรวมเข้ากับ Spring Framework 6.0 และ Spring Boot 3.0 ที่มีการสนับสนุนระดับเฟิร์สคลาส ดังนั้นนี่จึงเป็นโอกาสเหมาะที่จะตรวจสอบโปรเจ็กต์อย่างละเอียดในช่วง 2-3 เดือนก่อนการเปิดตัว

แม้ว่าการคอมไพล์แบบทันทีจะได้รับการเพิ่มประสิทธิภาพอย่างมากสำหรับสิ่งต่างๆ เช่น กระบวนการที่ใช้เวลานาน แต่ก็มีกรณีการใช้งานบางกรณีที่แอปพลิเคชันคอมไพล์ล่วงหน้าจะทำงานได้ดีกว่า ซึ่งเราจะกล่าวถึงใน Codelab

คุณจะได้เรียนรู้วิธีต่อไปนี้

  • ใช้ Cloud Shell
  • เปิดใช้ Cloud Run API
  • สร้างและทำให้แอป Spring Native ใช้งานได้
  • ทำให้แอปดังกล่าวใช้งานได้ใน Cloud Run

สิ่งที่คุณต้องมี

แบบสำรวจ

คุณจะใช้บทแนะนำนี้อย่างไร

คุณจะให้คะแนนประสบการณ์การใช้งาน Java อย่างไร

คุณจะให้คะแนนความพึงพอใจในการใช้บริการ Google Cloud อย่างไร

2 ข้อมูลเบื้องต้น

โปรเจ็กต์ Spring Native จะใช้เทคโนโลยีหลายๆ แบบเพื่อมอบประสิทธิภาพของแอปพลิเคชันแบบเนทีฟให้แก่นักพัฒนาซอฟต์แวร์

เราขอแนะนำให้ทำความเข้าใจกับเทคโนโลยีคอมโพเนนต์บางส่วนเหล่านี้ สิ่งที่ทำให้เกิดเรา และวิธีที่เทคโนโลยีดังกล่าวทำงานร่วมกันที่นี่ เพื่อทำความเข้าใจอย่างถ่องแท้

วิดีโอรวมคลิป AOT

เมื่อนักพัฒนาซอฟต์แวร์เรียกใช้ Javac ตามปกติในเวลาคอมไพล์ ระบบจะคอมไพล์ซอร์สโค้ด .java ของเราเป็นไฟล์ .class ซึ่งเขียนเป็นไบต์โค้ด ไบต์โค้ดนี้มีไว้เพื่อให้ Java Virtual Machine เข้าใจเท่านั้น ดังนั้น JVM จะต้องตีความโค้ดนี้บนเครื่องอื่นเพื่อให้เราเรียกใช้โค้ดได้

กระบวนการนี้ทำให้เรามีความสามารถในการถ่ายโอนแบบลายเซ็นของ Java ทำให้เราสามารถ "เขียนครั้งเดียวและทำงานได้ทุกที่" แต่มันมีค่าใช้จ่ายสูงเมื่อเทียบกับการเรียกใช้โค้ดแบบเนทีฟ

โชคดีที่การใช้งาน JVM ส่วนใหญ่ใช้การคอมไพล์แบบทันท่วงทีเพื่อลดค่าใช้จ่ายในการตีความนี้ ซึ่งทำได้โดยการนับการเรียกสำหรับฟังก์ชัน และหากมีการเรียกใช้บ่อยพอที่จะผ่านเกณฑ์ ( 10,000 ครั้งโดยค่าเริ่มต้น) ระบบจะคอมไพล์เป็นโค้ดแบบเนทีฟขณะรันไทม์เพื่อป้องกันการตีความค่าใช้จ่ายที่แพงกว่า

การคอมไพล์แบบล่วงหน้าจะใช้วิธีตรงกันข้าม โดยการรวบรวมโค้ดที่เข้าถึงได้ทั้งหมดลงในไฟล์ปฏิบัติการแบบเนทีฟในเวลาคอมไพล์ วิธีนี้ลดความสามารถในการถ่ายโอนได้เพื่อประหยัดหน่วยความจำและประสิทธิภาพอื่นๆ ที่เพิ่มขึ้นในขณะทำงาน

5042e8e62a05a27.png

แน่นอนว่านี่เป็นข้อดี และจะไม่คุ้มค่ากับการต้องรับ อย่างไรก็ตาม การรวบรวม AOT อาจมีประสิทธิภาพได้ในบางกรณี เช่น

  • แอปพลิเคชันที่มีอายุสั้นโดยที่เวลาเริ่มต้นเป็นสิ่งสำคัญ
  • สภาพแวดล้อมที่มีหน่วยความจำจำกัดสูงซึ่ง JIT อาจใช้ต้นทุนมากเกินไป

อันที่จริงแล้ว คลิปรวม AOT ได้รับการนำเสนอเป็นฟีเจอร์ทดลองใน JDK 9 แม้ว่าการติดตั้งใช้งานนี้จะมีค่าใช้จ่ายในการดูแลรักษาสูงและไม่ค่อยถูกจับต้อง ระบบจึงทยอยนำออกใน Java 17 เพื่อประโยชน์ของนักพัฒนาซอฟต์แวร์ที่ใช้ GraalVM เท่านั้น

GraalVM

GraalVM คือการกระจาย JDK แบบโอเพนซอร์สที่ได้รับการเพิ่มประสิทธิภาพขั้นสูง พร้อมเวลาเปิดเครื่องที่รวดเร็วมาก การคอมไพล์รูปภาพแบบ AOT ในเครื่อง และความสามารถด้านภาษาศาสตร์ที่ทำให้นักพัฒนาซอฟต์แวร์ผสมผสานภาษาต่างๆ ไว้ในแอปพลิเคชันเดียวได้

GraalVM อยู่ระหว่างการพัฒนา เพิ่มความสามารถใหม่ๆ และปรับปรุงความสามารถที่มีอยู่อยู่เสมอ ฉันจึงขอให้นักพัฒนาซอฟต์แวร์ติดตามความคืบหน้าอยู่เสมอ

เหตุการณ์สำคัญล่าสุดมีดังนี้

  • เอาต์พุตบิลด์ใหม่สำหรับอิมเมจเนทีฟที่ใช้งานง่าย ( 18-01-2021)
  • การรองรับ Java 17 ( 2022-01-18)
  • เปิดใช้การคอมไพล์แบบหลายชั้นโดยค่าเริ่มต้นเพื่อปรับปรุงเวลาคอมไพล์แบบหลายภาษา ( 20-04-2021)

เนทีฟช่วงฤดูใบไม้ผลิ

พูดง่ายๆ ก็คือ Spring Native ทำให้สามารถใช้คอมไพเลอร์รูปภาพแบบเนทีฟของ GraalVM เพื่อเปลี่ยนแอปพลิเคชัน Spring เป็นไฟล์สั่งการที่มาพร้อมเครื่อง

กระบวนการนี้จะต้องมีการวิเคราะห์แอปพลิเคชันแบบคงที่ในเวลาคอมไพล์เพื่อค้นหาวิธีการทั้งหมดในแอปพลิเคชันที่เข้าถึงได้จากจุดแรกเข้า

ซึ่งเป็นการสร้าง "โลกปิด" ขึ้นมาโดยหลัก แนวคิดของแอปพลิเคชันของคุณ ซึ่งจะถือว่ารู้โค้ดทั้งหมดในเวลาคอมไพล์ และจะไม่อนุญาตให้โหลดโค้ดใหม่ขณะรันไทม์

โปรดทราบว่าการสร้างรูปภาพในเครื่องเป็นกระบวนการที่ใช้หน่วยความจำมาก ซึ่งใช้เวลานานกว่าการคอมไพล์แอปพลิเคชันทั่วไป และกำหนดข้อจำกัดในบางแง่มุมของ Java

ในบางกรณี คุณไม่จำเป็นต้องเปลี่ยนแปลงโค้ดเพื่อให้แอปพลิเคชันทำงานร่วมกับ Spring Native ได้ อย่างไรก็ตาม บางสถานการณ์จำเป็นต้องมีการกำหนดค่าเนทีฟเฉพาะเพื่อให้ทำงานได้อย่างถูกต้อง ซึ่งในสถานการณ์เหล่านั้น โฆษณาเนทีฟในฤดูใบไม้ผลิมักจะให้คำแนะนำเนทีฟเพื่อลดความซับซ้อนของกระบวนการนี้

3 การตั้งค่า/งานล่วงหน้า

ก่อนที่จะเริ่มใช้โฆษณาเนทีฟในฤดูใบไม้ผลิ เราจะต้องสร้างและทำให้แอปใช้งานได้เพื่อสร้างเกณฑ์พื้นฐานด้านประสิทธิภาพที่เราจะนำไปเปรียบเทียบกับเวอร์ชันเนทีฟในภายหลังได้

1. สร้างโปรเจ็กต์

เราจะเริ่มต้นด้วยการรับแอปจาก start.spring.io:

curl https://start.spring.io/starter.zip -d dependencies=web \
           -d javaVersion=11 \
           -d bootVersion=2.6.4 -o io-native-starter.zip

แอปเริ่มต้นนี้ใช้ Spring Boot 2.6.4 ซึ่งเป็นเวอร์ชันล่าสุดที่โปรเจ็กต์ Spring-native รองรับในขณะที่เขียน

โปรดทราบว่านับตั้งแต่การเปิดตัว GraalVM 21.0.3 คุณสามารถใช้ Java 17 สำหรับตัวอย่างนี้ได้เช่นกัน เราจะยังคงใช้ Java 11 สำหรับบทแนะนำนี้เพื่อลดการกำหนดค่าที่เกี่ยวข้อง

เมื่อเรามีไฟล์ ZIP ในบรรทัดคำสั่งแล้ว เราก็สามารถสร้างไดเรกทอรีย่อยสำหรับโปรเจ็กต์ของเรา และแตกโฟลเดอร์ในนั้น:

mkdir spring-native

cd spring-native

unzip ../io-native-starter.zip

2. การเปลี่ยนแปลงโค้ด

หลังจากเปิดโปรเจ็กต์แล้ว เราจะเพิ่มสัญญาณแห่งชีวิตอย่างรวดเร็วและแสดงประสิทธิภาพของโฆษณาเนทีฟในฤดูใบไม้ผลิเมื่อเรียกใช้

แก้ไข DemoApplication.java ให้ตรงกับคำสั่งนี้

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.time.Instant;

@RestController
@SpringBootApplication
public class DemoApplication {
   
private static Instant startTime;
   
private static Instant readyTime;

   
public static void main(String[] args) {
       
startTime = Instant.now();
               
SpringApplication.run(DemoApplication.class, args);
   
}

   
@GetMapping("/")
   
public String index() {
       
return "Time between start and ApplicationReadyEvent: "
               
+ Duration.between(startTime, readyTime).toMillis()
               
+ "ms";
   
}

   
@EventListener(ApplicationReadyEvent.class)
   
public void ready() {
               
readyTime = Instant.now();
   
}
}

ในขั้นนี้แอปพื้นฐานของเราพร้อมแล้ว ดังนั้นให้สร้างอิมเมจและเรียกใช้ในเครื่องเพื่อทราบถึงช่วงเวลาเริ่มต้นก่อนที่เราจะแปลงแอปเป็นแอปพลิเคชันที่มาพร้อมเครื่อง

วิธีสร้างรูปภาพ

mvn spring-boot:build-image

คุณยังใช้ docker images demo เพื่อให้ทราบขนาดของรูปภาพพื้นฐานได้โดยทำดังนี้ 6ecb403e9af1475e.png

วิธีเรียกใช้แอป

docker run --rm -p 8080:8080 demo:0.0.1-SNAPSHOT

3. ทำให้แอปพื้นฐานใช้งานได้

ตอนนี้เรามีแอปแล้ว เราจะทำให้ใช้งานได้และจดบันทึกเวลาที่เราจะนำไปเปรียบเทียบกับเวลาเริ่มต้นของแอปที่มาพร้อมเครื่องในภายหลัง

มีหลายโฮสติ้งเนื้อหาของคุณ ทั้งนี้ขึ้นอยู่กับประเภทแอปพลิเคชันที่คุณสร้าง

อย่างไรก็ตาม เนื่องจากตัวอย่างของเราเป็นเว็บแอปพลิเคชันที่ง่ายและไม่ซับซ้อน เราจึงสามารถทำให้ทุกอย่างเรียบง่ายและใช้ Cloud Run ได้

หากติดตามด้วยเครื่องของคุณเอง โปรดตรวจสอบว่าได้ติดตั้งและอัปเดตเครื่องมือ gcloud CLI แล้ว

หากใช้ Cloud Shell ซึ่งจะได้รับการดูแลทั้งหมด และคุณสามารถเรียกใช้สิ่งต่อไปนี้ในไดเรกทอรีต้นทางได้

gcloud run deploy

4 การกำหนดค่าแอปพลิเคชัน

1. การกำหนดค่าที่เก็บ Maven ของเรา

เนื่องจากโปรเจ็กต์นี้ยังคงอยู่ในระยะทดลอง เราจึงจะต้องกำหนดค่าแอปให้ค้นหาอาร์ติแฟกต์ทดลองได้ ซึ่งไม่มีให้บริการในที่เก็บส่วนกลางของ Maven

ซึ่งรวมถึงการเพิ่มองค์ประกอบต่อไปนี้ลงใน pom.xml ของเรา ซึ่งคุณดำเนินการได้ในตัวแก้ไขที่ต้องการ

เพิ่มส่วน ที่เก็บข้อมูล และ PluginRepositories ต่อไปนี้ใน Pom ของเรา:

<repositories>
   
<repository>
       
<id>spring-release</id>
       
<name>Spring release</name>
       
<url>https://repo.spring.io/release</url>
   
</repository>
</repositories>

<pluginRepositories>
   
<pluginRepository>
       
<id>spring-release</id>
       
<name>Spring release</name>
       
<url>https://repo.spring.io/release</url>
   
</pluginRepository>
</pluginRepositories>

2. การเพิ่มทรัพยากร Dependency

ถัดไป ให้เพิ่มทรัพยากร Dependency สำหรับฤดูใบไม้ผลิซึ่งจำเป็นสำหรับการเรียกใช้แอปพลิเคชัน Spring เป็นรูปภาพเนทีฟ หมายเหตุ: ขั้นตอนนี้ไม่จำเป็นหากใช้ Gradle

<dependencies>
   
<!-- ... -->
   
<dependency>
       
<groupId>org.springframework.experimental</groupId>
       
<artifactId>spring-native</artifactId>
       
<version>0.11.2</version>
   
</dependency>
</dependencies>

3. การเพิ่ม/เปิดใช้ปลั๊กอิน

ตอนนี้ให้เพิ่มปลั๊กอิน AOT เพื่อปรับปรุงความเข้ากันได้และฟุตพริ้นท์ของรูปภาพดั้งเดิม ( อ่านเพิ่มเติม)

<plugins>
   
<!-- ... -->
   
<plugin>
       
<groupId>org.springframework.experimental</groupId>
       
<artifactId>spring-aot-maven-plugin</artifactId>
       
<version>0.11.2</version>
       
<executions>
           
<execution>
               
<id>generate</id>
               
<goals>
                   
<goal>generate</goal>
               
</goals>
           
</execution>
       
</executions>
   
</plugin>
</plugins>

ตอนนี้เราจะอัปเดตปลั๊กอิน spring-boot-maven-plugin เพื่อเปิดใช้การรองรับอิมเมจในเครื่องและใช้เครื่องมือสร้าง paketo เพื่อสร้างอิมเมจเนทีฟ

<plugins>
   
<!-- ... -->
   
<plugin>
       
<groupId>org.springframework.boot</groupId>
       
<artifactId>spring-boot-maven-plugin</artifactId>
       
<configuration>
           
<image>
               
<builder>paketobuildpacks/builder:tiny</builder>
               
<env>
                   
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
               
</env>
           
</image>
       
</configuration>
   
</plugin>    
</plugins>

โปรดทราบว่ารูปภาพเครื่องมือสร้างขนาดเล็กเป็นเพียงหนึ่งในตัวเลือกหลายๆ ตัวเลือก ตัวเลือกนี้เหมาะสำหรับ Use Case ของเราเพราะมีไลบรารีและยูทิลิตีเพิ่มเติมน้อยมาก ซึ่งช่วยลดพื้นที่ในการโจมตี

ตัวอย่างเช่น ถ้าคุณกำลังสร้างแอปที่ต้องเข้าถึงไลบรารี C ทั่วไปบางรายการ และคุณยังไม่แน่ใจเกี่ยวกับข้อกำหนดของแอป เครื่องมือสร้างแบบเต็มรูปแบบอาจเหมาะสมกว่า

5 สร้างและเรียกใช้แอปที่มาพร้อมเครื่อง

เมื่อทุกอย่างพร้อมแล้ว เราควรจะสามารถสร้างอิมเมจและเรียกใช้แอปที่มาพร้อมเครื่องซึ่งคอมไพล์ได้

ก่อนเรียกใช้บิลด์ โปรดคำนึงถึงสิ่งต่อไปนี้

  • การดำเนินการนี้จะใช้เวลามากกว่าบิลด์ปกติ (2-3 นาที) d420322893640701.png
  • กระบวนการบิลด์นี้ใช้หน่วยความจำจำนวนมาก (ไม่กี่กิกะไบต์) cda24e1eb11fdbea.png
  • กระบวนการบิลด์นี้กำหนดให้เข้าถึง Daemon ของ Docker ได้
  • ในตัวอย่างนี้เรากำลังทำกระบวนการด้วยตนเอง คุณยังสามารถกำหนดค่าเฟสของบิลด์ให้ทริกเกอร์โปรไฟล์บิลด์เนทีฟโดยอัตโนมัติได้ด้วย

วิธีสร้างรูปภาพ

mvn spring-boot:build-image

เมื่อสร้างเสร็จแล้ว เราพร้อมที่จะเห็นการทำงานของแอปที่มาพร้อมเครื่องแล้ว

วิธีเรียกใช้แอป

docker run --rm -p 8080:8080 demo:0.0.1-SNAPSHOT

ณ จุดนี้ เราอยู่ในตำแหน่งที่ยอดเยี่ยมที่จะได้เห็นสมการการประยุกต์ใช้แบบเดิมทั้ง 2 ด้านแล้ว

เราไม่ได้ให้เวลาและมีการใช้หน่วยความจำเพิ่มขึ้นเล็กน้อยในเวลาคอมไพล์ แต่ในทางกลับกัน เราได้รับแอปพลิเคชันที่เริ่มทำงานได้เร็วกว่ามากและใช้หน่วยความจำน้อยลงมาก (ขึ้นอยู่กับปริมาณงาน)

หากเราเรียกใช้ docker images demo เพื่อเปรียบเทียบขนาดของรูปภาพต้นฉบับกับต้นฉบับ เราจะเห็นการลดลงอย่างมาก

e667f65a011c1328.png

นอกจากนี้เรายังควรทราบด้วยว่าในกรณีการใช้งานที่ซับซ้อนมากขึ้น จะต้องมีการแก้ไขเพิ่มเติมเพื่อแจ้งให้คอมไพเลอร์ AOT ทราบถึงสิ่งที่แอปของคุณจะทำในระหว่างรันไทม์ ด้วยเหตุนี้ ภาระงานที่คาดเดาได้บางอย่าง (เช่น งานแบบกลุ่ม) อาจเหมาะกับกรณีนี้มาก แต่หากภาระงานอื่นๆ อาจใช้เวลานานกว่านี้

6 การทำให้แอปที่มาพร้อมเครื่องของเราใช้งานได้

ในการทำให้แอปของเราใช้งานได้ใน Cloud Run เราจะต้องนำอิมเมจในเครื่องเข้าสู่เครื่องมือจัดการแพ็กเกจ เช่น Artifact Registry

1. กำลังเตรียมที่เก็บ Docker

เราสามารถเริ่มกระบวนการนี้โดยการสร้างที่เก็บ:

gcloud artifacts repositories create native-image-docker-repo --repository-format=docker \
--location=us-central1 --description="Repository for our native images"

ถัดไป เราต้องการตรวจสอบว่าผ่านการตรวจสอบสิทธิ์เพื่อพุชไปยังรีจิสทรีใหม่แล้ว

ซึ่ง gcloud CLI จะช่วยลดความซับซ้อนของกระบวนการดังกล่าวไปเล็กน้อยได้โดยทำดังนี้

gcloud auth configure-docker us-central1-docker.pkg.dev

2. พุชอิมเมจของเราไปยัง Artifact Registry

ต่อไป เราจะติดแท็กรูปภาพของเรา ดังนี้

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')


docker tag  demo:0.0.1-SNAPSHOT \
us-central1-docker.pkg.dev/$PROJECT_ID/native-image-docker-repo/quickstart-image:tag2

จากนั้นเราจะใช้ docker push เพื่อส่งไปยัง Artifact Registry ดังนี้

docker push us-central1-docker.pkg.dev/$PROJECT_ID/native-image-docker-repo/quickstart-image:tag2

3. การทำให้ใช้งานได้กับ Cloud Run

ตอนนี้เราพร้อมที่จะทำให้อิมเมจที่เราจัดเก็บไว้ใน Artifact Registry ใช้งานได้ไปยัง Cloud Run แล้ว โดยทำดังนี้

gcloud run deploy --image us-central1-docker.pkg.dev/$PROJECT_ID/native-image-docker-repo/quickstart-image:tag2

เนื่องจากเราได้สร้างและปรับใช้แอปของเราเป็นอิมเมจในเครื่อง เราจึงมั่นใจได้ว่าแอปพลิเคชันของเราใช้ต้นทุนด้านโครงสร้างพื้นฐานได้อย่างยอดเยี่ยมในขณะที่ทำงาน

คุณสามารถเปรียบเทียบเวลาเริ่มต้นของแอปพื้นฐานของเรากับเวลาเริ่มต้นของแอปใหม่ๆ ได้ด้วยตัวคุณเอง

6dde63d35959b1bb.png

7 สรุป/ล้างข้อมูล

ขอแสดงความยินดีกับการสร้างและทำให้แอปพลิเคชัน Spring Native ใช้งานได้ใน Google Cloud

เราหวังว่าบทแนะนำนี้จะช่วยส่งเสริมให้คุณทำความคุ้นเคยกับโปรเจ็กต์ Spring Native และอย่าลืมคำนึงถึงสิ่งนี้หากสิ่งนี้ตอบสนองความต้องการของคุณในอนาคต

ไม่บังคับ: ล้างข้อมูลและ/หรือปิดใช้บริการ

ไม่ว่าคุณจะสร้างโปรเจ็กต์ Google Cloud สําหรับ Codelab นี้หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ โปรดระมัดระวังเพื่อหลีกเลี่ยงการเรียกเก็บเงินที่ไม่จำเป็นจากทรัพยากรที่เราใช้

คุณสามารถลบหรือปิดใช้บริการ Cloud Run ที่เราสร้าง ลบอิมเมจที่เราโฮสต์ไว้ หรือปิดทั้งโปรเจ็กต์

8 แหล่งข้อมูลเพิ่มเติม

แม้ว่าในตอนนี้โปรเจ็กต์ Spring Native จะเป็นโปรเจ็กต์ทดลองใหม่ๆ แต่ก็มีแหล่งข้อมูลดีๆ มากมายที่จะช่วยผู้ใช้นำร่องแก้ปัญหาและเข้ามามีส่วนร่วมได้ ดังนี้

แหล่งข้อมูลเพิ่มเติม

ด้านล่างนี้คือแหล่งข้อมูลออนไลน์ที่อาจเกี่ยวข้องกับบทแนะนำนี้

ใบอนุญาต

ผลงานนี้ได้รับอนุญาตภายใต้ใบอนุญาตทั่วไปครีเอทีฟคอมมอนส์แบบระบุแหล่งที่มา 2.0