Reload java classes ของ Spring Boot โดยไม่ต้อง Restart Server

ในการเขียนโค้ดสิ่งที่ทำให้ผมเสียเวลามากที่สุดถ้าไม่นับการ search วิธีแก้ปัญหาก็คงเป็นการรอ Server ให้ start เสร็จเพื่อที่จะได้ทดสอบโค้ดนั้น จนถึงขั้นมีคนทำ JRebel ระบบที่ไม่ต้อง restart ก็อัพเดทโค้ดใหม่ได้ออกมาขาย ครั้นจะซื้อมาใช้ในการทำงานจริงก็สู้ราคา License ไม่ไหว

พอดีวันนี้ได้รับแรงบันดาลใจจาก Coding with Notch (from Minecraft: The Story of Mojang) ที่เขียนโค้ดบน Eclipse แล้วแก้ไขโดยแทบไม่ต้อง stop เกมส์ แต่ก็มีบางจังหวะที่เห็น stop เนื่องจากเป็นข้อจำกัดของระบบ hot swap ของ Eclipse เอง majong

ผมจึงลองค้นหาใน Document ว่า Spring Boot มีความสามารถแบบนี้หรือไม่ ซึ่งผมก็พบแสงสว่างที่ชื่อว่า Springloaded ซึ่งเป็นตัว reload ที่ใช้ใน Grails 2 แต่ก็สามารถเอามาใช้กับ Spring Boot ได้เช่นกัน

ปัญหาอยู่ที่ว่า ผมไม่สามารถทำตาม document ของ spring boot ได้ เนื่องจากเป็นการชี้ช่องทางไม่ได้บอกวิธีทำ ผมจริงต้องลงมือศึกษาเพิ่มเติมจนได้วิธีนี้มา วิธีการสรุปสั้นๆ คือไปโหลด jar ของ springloaded มาแล้วเพิ่มคำสั่ง vm argument agent เข้าไป

เครื่องมือที่ใช้


  • JDK 8
  • Spring Tool Suite 3.5.4

ถ้าไม่ได้ใช้ eclipse jee ธรรมดาก็ไปใช้บริการเว็บ http://start.spring.io/ ก็ได้ครับ

วิธีทำ


  1. สร้าง Spring Boot โปรเจคขึ้นมา
  2. เนื่องจาก Spring Boot ผมใช้ Maven ผมจึงเลือกที่จะโหลดผ่าน Dependency โดยเปิดไฟล์ pom.xml ขึ้นมาแล้วเพิ่มเข้าไป
    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>springloaded</artifactId>
    </dependency>
    
  3. สร้าง Controller ง่ายๆ ขึ้นมาหนึ่งตัวเพื่อบูชา Hello World ดังนี้
    package com.magicalcyber.school.web;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class HomeController {
    	
    	@RequestMapping("/")
    	public String home(Model model) {
    		model.addAttribute("msg", "Hello, World!");
    		return "home";
    	}
    	
    }
    
    
  4. สร้าง view หนึ่งตัวเพื่อแสดงผล (ผมใช้ thymeleaf หน้าตาอาจจะแปลกๆ ไม่ต้องแปลกใจนะครับ)
    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
    <meta charset="UTF-8" />
    <title>Home</title>
    </head>
    <body>
    <p th:text="${msg}"></p>
    </body>
    </html>
    
  5. ทดสอบ Start Server เพื่อบูชาว่าเรา setup ได้ถูกต้องแล้ว Screen Shot 2015-04-14 at 9.32.10 PM
  6. ทำการ Stop Server แล้วไปตามล่าหา path ของ springloaded ใน repository (หรือที่โหลดมาไว้เอง) แล้วจำตำแหน่ง jar ไว้
  7. กลับไปที่ Eclipse เลือก Run Configuration Screen Shot 2015-04-14 at 9.35.38 PM
  8. เลือก spring boot ที่ท่านทำการรันในครั้งแรกแล้วเลือก tab arguments ในช่อง VM arguments: ให้ใส่คำสั่งพร้อมระบุ path ของ springloaded.jar ดังนี้ -javaagent:/path/to/.m2/repository/org/springframework/springloaded/1.2.1.RELEASE/springloaded-1.2.1.RELEASE.jar -noverify ของเครื่องผมก็จะเป็นดังนี้ แล้วก็กดปุ่ม Run (อย่าลืม stop server ตัวเก่าก่อนนะครับ) Screen Shot 2015-04-14 at 9.41.13 PM
  9. สิ่งที่ผมสังเกตได้บนเครื่องผมคือ หากระบุ path ถูกต้อง ใน console จะมีบรรทัดหนึ่งโผล่ขึ้นมาก่อน banner ของ spring boot ดังนี้ Screen Shot 2015-04-14 at 9.43.38 PM จากนั้นกลับไป refresh หน้าจอ http://localhost:8080 ควรจะทำงานได้ตามปกติ

Springloaded


เพื่อให้ดูง่ายผมขอแยกมาอีกหัวข้อหนึ่ง สรุปหัวข้อที่แล้วคือการเพิ่ม vm arguments เพื่อเรียก springloaded.jar คราวนี้คือการแก้ไข controller ซึ่งเป็น java class โดยที่ไม่ต้อง start server ใหม่

  1. จากหัวข้อเดิม ผมยังไม่ได้ทำการ stop server ผมทำการแก้ไขค่า msg เป็น "Hello, MagicalCyber!" เมื่อผมทำการบันทึกก็จะพบว่า log มาการ reload class นี้ใหม่ (และ eclipse ต้องเปิดโหมด Build Automatically ด้วย ไม่อย่างนั้นต้องทำการ build ก่อน) Screen Shot 2015-04-14 at 9.51.47 PM
  2. Refresh หน้า Browser ก็จะเปลี่ยนข้อความแล้ว Screen Shot 2015-04-14 at 9.54.28 PM
  3. ผมทดสอบเพิ่ม method ใหม่ดังนี้
    @RequestMapping("/hello/{name}")
       public String hello(@PathVariable String name, Model model){
       model.addAttribute("msg", "Hello, " + name);
       return "home";
    }
    
  4. เมื่อผมกดบันทึกและเรียก url ที่เพิ่มเข้ามาใหม่ ก็จะพบว่าสามารถทำงานได้ทันทีโดยไม่ต้อง restart server Screen Shot 2015-04-14 at 9.59.09 PM

ส่งท้าย


ผมว่าเป็นอะไรที่ประทับใจมาก ที่เราสามารถเขียนโปรแกรมแล้วไม่ต้อง restart server ใหม่ โดย springreloaded สามารถช่วยประหยัดเวลาได้มาก ซึ่งหากเทียบกับระบบ hot swapping ของ Editor สมัยใหม่ก็ถือว่าข้ามข้อจำกัดไปได้เยอะ อย่างเช่น เปลี่ยน method signature หรือเพิ่ม method ใหม่ และถึงแม้จะยังเทียบขั้นพี่ใหญ่อย่าง JRebel ได้แต่สำหรับผมแค่นี้ก็ดีใจมากแล้ว ซึ่งการทำงานบางอย่างใช่ว่าจะไม่ต้อง Restart เลยที่เรียกว่าเป็นข้อจำกัดที่ผมพบก็คือ Hibernate (JPA) ที่จะสร้าง table ใหม่ หรือเมื่อมีการเพิ่ม Field ใหม่ เป็นต้น ศึกษาเพิ่มเติมได้จากลิงก์อ้างอิงครับ

อ้างอิง


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s