Spring Boot แยก environments dev ,staging ,prod ด้วย spring profiles EP3

Sharing is caring!

เมื่อการพัฒนาระบบ ได้มาถึงจุดที่ต้องทำการแยก environments ที่แตกต่างกัน จากตัวอย่างที่เห็นได้ชัด ๆ เช่น endpoint ของ API ที่ dev ก็จะใช้เป็น endpoint เพื่อสำหรับ dev เท่านั้น แต่เมื่ออยากที่จะ deploy เพื่อใช้งานบน production ก็จะมี endpoint ของ API เวอร์ชั่นที่เป็น ของ production จริงและความต้องการแบบนี้ สำหรับ project ที่ build ด้วย spring boot จะแก้ปัญหาได้อย่างไร มาทำความรู้จัก spring profiles กัน เพื่อช่วยให้ระบบสามารถแยก constant variables ตาม environment ต้องทำอย่างไร

ทดลองสร้าง Simple Project เพื่อพิสูจน์ความต้องการในครั้งนี้

โดยปกติ spring boot เมื่อสร้าง project ด้วย spring initialize เช็คโครงสร้าง project จะสังเกตุเห็นไฟล์ src/main/resources/application.properties ถ้าเราต้องการที่จะแยก environment dev , staging ,prod ก็ต้องจัดการไฟล์นี้ใหม่

  • เพิ่มไฟล์ตาม environment ที่ต้องการ ตัวอย่างข้างล่างนี้จะทำตัวอย่าง แยก dev ,prod เพื่อใช้เป็นตัวอย่างง่าย ๆ โดยจะทำการ copy file application.properties มาตั้งชื่อใหม่ให้เป็นตามแต่ละ environment แบบนี้
    • dev: src/main/resources/application-dev.properties
    • prod: src/main/resources/application-prod.properties
  • เพิ่มเติมเนื้อหาข้างในไฟล์ application-dev.properties และ application-prod.properties
#file application-dev.properties
server.port=8090
api.endpoint="dev.poolsawat.com"
#file application-prod.properties
server.port=9090
api.endpoint="prod.poolsawat.com"

โดยกำหนดให้

server.port ของ dev start ที่ port 8090 , prod start ที่ port 9090

api.endpoint ของ dev ใช้ endpoint ที่ “dev.poolsawat.com” , prod จะใช้ที่ “prod.poolsawat.com”

  • แก้ไขไฟล์ Application.java (ไฟล์ สำหรับใช้ boot SpringApplication.run(PoolsawatApplication.class, args); )
package com.poolsawat.starter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class PoolsawatApplication implements CommandLineRunner{
	
	private static final Logger logger = LoggerFactory.getLogger(PoolsawatApplication.class);
	
	@Value("${api.endpoint}")
	private String apiEndpointUrl;
	
	@Value("${server.port}")
	private String serverPort;

	public static void main(String[] args) {
		SpringApplication.run(PoolsawatApplication.class, args);
	}
	
	@Override
	public void run(String... args) throws Exception {
		logger.info("server.port ::=="+serverPort);
		logger.info("api.endpoint ::=="+apiEndpointUrl);
		logger.info("spring boot loaded");
	}
	
}

เริ่มสั่ง start server ที่ env dev (ส่ง argrument -Dspring-boot.run.profiles=dev)

$ mvn -s D:/pool13433/programs/.m2/settings.xml spring-boot:run -Dspring-boot.run.profiles=dev
...
2021-03-08 13:29:35.407  INFO 12204 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-03-08 13:29:35.504  INFO 12204 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8090 (http) with context path ''
2021-03-08 13:29:35.512  INFO 12204 --- [           main] c.p.starter.PoolsawatApplication         : Started PoolsawatApplication in 1.253 seconds (JVM running for 1.518)
2021-03-08 13:29:35.514  INFO 12204 --- [           main] c.p.starter.PoolsawatApplication         : server.port ::==8090
2021-03-08 13:29:35.514  INFO 12204 --- [           main] c.p.starter.PoolsawatApplication         : api.endpoint ::=="dev.poolsawat.com"
2021-03-08 13:29:35.514  INFO 12204 --- [           main] c.p.starter.PoolsawatApplication         : spring boot loaded

เริ่มสั่ง start server ที่ env prod (ส่ง argrument -Dspring.profiles.active=prod)

  • pack jar ด้วย mvn install
  • exc jar
$ mvn -s D:/pool13433/programs/.m2/settings.xml install -Dmaven.test.skip=true
...
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ poolsawat ---
[INFO] Installing D:\pool13433\aging\workspace\Poolsawat.Com\target\poolsawat.jar to D:\pool13433\programs\.m2\repository\com\poolsawat\poolsawat\0.0.1-SNAPSHOT\poolsawat-0.0.1-SNAPSHOT.jar
[INFO] Installing D:\pool13433\aging\workspace\Poolsawat.Com\pom.xml to D:\pool13433\programs\.m2\repository\com\poolsawat\poolsawat\0.0.1-SNAPSHOT\poolsawat-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
$ java -jar -Dspring.profiles.active=prod ./target/poolsawat.jar
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.3)

2021-03-08 13:33:49.548  INFO 7448 --- [           main] c.p.starter.PoolsawatApplication         : Starting PoolsawatApplication v0.0.1-SNAPSHOT using Java 1.8.0_281 on LAPTOP-69PUN6C7 with PID 7448 (D:\pool13433\aging\workspace\Poolsawat.Com\target\poolsawat.jar started by pool13433 in D:\pool13433\aging\workspace\Poolsawat.Com)
2021-03-08 13:33:49.550  INFO 7448 --- [           main] c.p.starter.PoolsawatApplication         : The following profiles are active: prod
2021-03-08 13:33:50.698  INFO 7448 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9090 (http)
2021-03-08 13:33:50.716  INFO 7448 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-03-08 13:33:50.717  INFO 7448 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.43]
2021-03-08 13:33:50.807  INFO 7448 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-03-08 13:33:50.807  INFO 7448 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1191 ms
2021-03-08 13:33:50.993  INFO 7448 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-03-08 13:33:51.156  INFO 7448 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9090 (http) with context path ''
2021-03-08 13:33:51.167  INFO 7448 --- [           main] c.p.starter.PoolsawatApplication         : Started PoolsawatApplication in 2.062 seconds (JVM running for 2.484)
2021-03-08 13:33:51.168  INFO 7448 --- [           main] c.p.starter.PoolsawatApplication         : server.port ::==9090
2021-03-08 13:33:51.169  INFO 7448 --- [           main] c.p.starter.PoolsawatApplication         : api.endpoint ::=="prod.poolsawat.com"
2021-03-08 13:33:51.169  INFO 7448 --- [           main] c.p.starter.PoolsawatApplication         : spring boot loaded

สรุปท้ายบทความ

วิธีการที่นำเสนอนี้เป็นเพียงวิธีการแยก environment แบบนึง สามารถทำด้วยวิธีแบบอื่น ๆ ได้ แต่ผมมองว่ามันจะเป็นวิธีการที่เข้าใจง่ายที่สุด หากผู้อ่านท่านใดลองนำไปทำตามแล้วเกิดติดปัญหา สามารถฝากคำถามไว้ครับ ขอบคุณสำหรับการติดตามบทความครับ

Github code

ใส่ความเห็น

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