๐ฑ Spring Boot Externalized Configuration: ์ธ๋ถ ์ค์ ๊ด๋ฆฌ์ ์ธ๊ณ๋ก ํ๋ฉ! ๐โโ๏ธ

๐ฑ Spring Boot Externalized Configuration: ์ธ๋ถ ์ค์ ๊ด๋ฆฌ์ ์ธ๊ณ๋ก ํ๋ฉ! ๐โโ๏ธ
์๋ ํ์ธ์, ๊ฐ๋ฐ์ ์ฌ๋ฌ๋ถ! ์ค๋์ Spring Boot์ ๊ฟํ ์ค์์๋ ๊ฟ์ค์ ๊ฟ์ธ Externalized Configuration์ ๋ํด ๊น์ด ํํค์ณ๋ณผ ๊ฑฐ์์. ์ด๊ฑฐ ์๋ฉด ์ฌ๋ฌ๋ถ์ ๊ฐ๋ฐ ์ธ์์ด 180๋ ๋ฌ๋ผ์ง ๊ฑฐ์์, ์ง์ง๋ฃจ์! ใ ใ ใ
์, ๊ทธ๋ฆฌ๊ณ ์ ๊น! ์ฌ๋ฌ๋ถ, ํน์ ๋ค์ํ ์ฌ๋ฅ์ ๊ฑฐ๋ํ ์ ์๋ ํ๋ซํผ ์ฐพ๊ณ ๊ณ์ จ์ด์? ๊ทธ๋ ๋ค๋ฉด ์ฌ๋ฅ๋ท์ ํ๋ฒ ์ฒดํฌํด๋ณด์ธ์! ๊ฐ๋ฐ ๊ด๋ จ ์ง์๋ถํฐ ๋ค์ํ ๋ถ์ผ์ ์ฌ๋ฅ๊น์ง, ์ฌ๋ฌ๋ถ์ ์ค๋ ฅ์ ๋ฝ๋ด๊ณ ์๋ก์ด ๊ฒ์ ๋ฐฐ์ธ ์ ์๋ ๊ณณ์ด์์. ๐จโ๐ซ๐ฉโ๐จ
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก Spring Boot์ ์ธ๋ถ ์ค์ ๊ด๋ฆฌ์ ๋ํด ์์๋ณผ๊น์? ์ค๋น๋์ จ๋์? 3, 2, 1... ๊ณ ๊ณ ์ฝ! ๐
1. Externalized Configuration์ด ๋ญ๊ธธ๋? ๐ค
์ฌ๋ฌ๋ถ, ํน์ ์ด๋ฐ ๊ฒฝํ ์์ผ์ธ์? ๊ฐ๋ฐํ ๋๋ ์ ๋์๊ฐ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ค์ ์๋ฒ์ ์ฌ๋ฆฌ๋ฉด ๊ฐ์๊ธฐ "์! ์ด๊ฒ ์ ์ ๋ผ?!" ํ๋ฉด์ ๋ฉ๋ถ์ค๋ ๊ทธ๋ฐ ์ํฉ... ๐ฑ
๋ฐ๋ก ์ด๋ฐ ์ํฉ์ ํด๊ฒฐํด์ฃผ๋ ๊ฒ Externalized Configuration์ด์์! ์ด๊ฒ ๋ญ๋๊ณ ์? ๊ฐ๋จํ ๋งํด์, ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ ์ ์ธ๋ถ์์ ๊ด๋ฆฌํ ์ ์๊ฒ ํด์ฃผ๋ ๊ธฐ๋ฅ์ด์์.
๐ฏ Externalized Configuration์ ํต์ฌ ํฌ์ธํธ:
- ์ฝ๋ ๋ณ๊ฒฝ ์์ด ์ค์ ๋ณ๊ฒฝ ๊ฐ๋ฅ
- ํ๊ฒฝ๋ณ๋ก ๋ค๋ฅธ ์ค์ ์ ์ฉ ์ฌ์
- ๋ณด์์ ๋ฏผ๊ฐํ ์ ๋ณด ๋ถ๋ฆฌ ๊ฐ๋ฅ
์ด๊ฒ ์ ์ค์ํ๋๊ณ ์? ์๋ฅผ ๋ค์ด๋ณผ๊ฒ์. ์ฌ๋ฌ๋ถ์ด ์ดํน๊ธ ๊ฐ๋ฐ์๊ฐ ๋์ด์ ์์ฒญ๋ ์๋น์ค๋ฅผ ๋ง๋ค์๋ค๊ณ ํด๋ด์. ๋ก์ปฌ์์ ๊ฐ๋ฐํ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฃผ์๊ฐ "localhost"์๋๋ฐ, ์ค์ ์๋ฒ์์๋ "super-secure-db.company.com"์ด์์. ์ด๋ด ๋ ์ฝ๋๋ฅผ ์ผ์ผ์ด ์์ ํ๊ณ ๋ค์ ๋น๋ํด์ผ ํ๋ค๋ฉด? ๐ซ ์๊ฐ๋ง ํด๋ ๋์ฐํ์ฃ ?
๋ฐ๋ก ์ด๋ฐ ์ํฉ์์ Externalized Configuration์ด ๋น์ ๋ฐํ๋ ๊ฑฐ์์! ์ค์ ๋ง ๋ฐ๊พธ๋ฉด ๋! ์ฝ๋ ํ ์ค ์ ๊ฑด๋๋ฆฌ๊ณ ๋ ํ๊ฒฝ์ ๋ง๋ ์ค์ ์ ์ ์ฉํ ์ ์๋ต๋๋ค. ๐
2. Spring Boot์์ ์ค์ ํ์ผ ์ฌ์ฉํ๊ธฐ ๐
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก Spring Boot์์ ์ด๋ป๊ฒ ์ธ๋ถ ์ค์ ์ ์ฌ์ฉํ๋์ง ์์๋ณผ๊น์? Spring Boot๋ ์ ๋ง ๋๋ํด์ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ์ค์ ์ ๋ถ๋ฌ์ฌ ์ ์์ด์. ๊ทธ์ค์์๋ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋ ๋ฐฉ๋ฒ์ ๋ฐ๋ก properties ํ์ผ๊ณผ YAML ํ์ผ์ ์ฌ์ฉํ๋ ๊ฑฐ์์.
2.1 Properties ํ์ผ ์ฌ์ฉํ๊ธฐ ๐๏ธ
properties ํ์ผ์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ์ค์ ํ์ผ ํ์์ด์์. ํค-๊ฐ ์์ผ๋ก ์ด๋ฃจ์ด์ ธ ์์ฃ . ์๋ฅผ ๋ค์ด๋ณผ๊น์?
# application.properties
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password
์ด๋ ๊ฒ ์์ฑ๋ properties ํ์ผ์ src/main/resources ๋๋ ํ ๋ฆฌ์ ๋ฃ์ผ๋ฉด Spring Boot๊ฐ ์๋์ผ๋ก ์ฝ์ด๋ค์ฌ์. ์์ฒญ ํธํ์ฃ ? ๐
2.2 YAML ํ์ผ ์ฌ์ฉํ๊ธฐ ๐
YAML ํ์ผ์ properties ํ์ผ๋ณด๋ค ์ข ๋ ๊ตฌ์กฐ์ ์ด๊ณ ๊ฐ๋ ์ฑ์ด ์ข์์. ๊ฐ์ ์ค์ ์ YAML๋ก ์์ฑํ๋ฉด ์ด๋ ๊ฒ ๋ฉ๋๋ค:
# application.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
์ด๋์? ๋ญ๊ฐ ๋ ๊น๋ํด ๋ณด์ด์ง ์๋์? ํนํ ๊ณ์ธต ๊ตฌ์กฐ๊ฐ ์๋ ์ค์ ์ ์์ฑํ ๋๋ YAML์ด ํจ์ฌ ๋ณด๊ธฐ ์ข๋ต๋๋ค. ๐
๐ก ๊ฟํ: properties ํ์ผ๊ณผ YAML ํ์ผ ์ค ์ด๋ค ๊ฑธ ์ฌ์ฉํ ์ง ๊ณ ๋ฏผ๋๋ค๊ณ ์? ๊ฑฑ์ ๋ง์ธ์! Spring Boot๋ ๋ ๋ค ์ง์ํ๋๊น ์ฌ๋ฌ๋ถ์ ์ทจํฅ๋๋ก ์ ํํ๋ฉด ๋ผ์. ๊ฐ์ธ์ ์ผ๋ก๋ YAML์ ์ถ์ฒํฉ๋๋ค. ์๋๊ณ ์? ๋ ์์๋๊น์! ใ ใ ใ
3. ํ๋กํ(Profile)๋ก ํ๊ฒฝ๋ณ ์ค์ ๊ด๋ฆฌํ๊ธฐ ๐
์ฌ๋ฌ๋ถ, ๊ฐ๋ฐํ ๋ ๋ก์ปฌ, ๊ฐ๋ฐ ์๋ฒ, ์คํ ์ด์ง ์๋ฒ, ํ๋ก๋์ ์๋ฒ... ์ด๋ ๊ฒ ์ฌ๋ฌ ํ๊ฒฝ์ ์ฌ์ฉํ์์ฃ ? ๊ฐ ํ๊ฒฝ๋ง๋ค ์ค์ ์ด ๋ค๋ฅผ ํ ๋ฐ, ์ด๊ฑธ ์ด๋ป๊ฒ ๊ด๋ฆฌํ๋ฉด ์ข์๊น์? ๋ฐ๋ก ์ด๋ Spring Boot์ ํ๋กํ(Profile) ๊ธฐ๋ฅ์ด ๋น์ ๋ฐํฉ๋๋ค! โจ
3.1 ํ๋กํ์ด๋? ๐ญ
ํ๋กํ์ ๊ฐ๋จํ ๋งํด์ ํน์ ํ๊ฒฝ์ ๋ํ ์ค์ ๋ฌถ์์ด์์. ์๋ฅผ ๋ค์ด, ๊ฐ๋ฐ ํ๊ฒฝ์ฉ ํ๋กํ, ํ ์คํธ ํ๊ฒฝ์ฉ ํ๋กํ, ์ด์ ํ๊ฒฝ์ฉ ํ๋กํ ๋ฑ์ ๋ง๋ค ์ ์์ฃ . ์ด๋ ๊ฒ ํ๋ฉด ํ๊ฒฝ๋ณ๋ก ๋ค๋ฅธ ์ค์ ์ ์ฝ๊ฒ ์ ์ฉํ ์ ์์ด์.
3.2 ํ๋กํ ์ค์ ํ์ผ ๋ง๋ค๊ธฐ ๐
ํ๋กํ๋ณ ์ค์ ํ์ผ์ ์ด๋ ๊ฒ ๋ง๋ค์ด์:
application-dev.properties(๋๋application-dev.yml): ๊ฐ๋ฐ ํ๊ฒฝ ์ค์ application-test.properties(๋๋application-test.yml): ํ ์คํธ ํ๊ฒฝ ์ค์ application-prod.properties(๋๋application-prod.yml): ์ด์ ํ๊ฒฝ ์ค์
๊ฐ ํ์ผ์๋ ํด๋น ํ๊ฒฝ์ ๋ง๋ ์ค์ ์ ๋ฃ์ผ๋ฉด ๋ผ์. ์๋ฅผ ๋ค์ด๋ณผ๊น์?
# application-dev.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/devdb
username: devuser
password: devpass
# application-prod.yml
spring:
datasource:
url: jdbc:mysql://prod-server:3306/proddb
username: produser
password: supersecret
3.3 ํ๋กํ ํ์ฑํํ๊ธฐ ๐
์, ์ด์ ํ๋กํ์ ์ด๋ป๊ฒ ํ์ฑํํ ๊น์? ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ด์:
- application.properties (๋๋ application.yml)์์ ์ค์ :
spring.profiles.active=dev - ํ๊ฒฝ ๋ณ์๋ก ์ค์ :
export SPRING_PROFILES_ACTIVE=prod - Java ๋ช
๋ น์ด๋ก ์คํํ ๋ ์ค์ :
java -jar myapp.jar --spring.profiles.active=test
์ด๋ ๊ฒ ํ๋ฉด ํด๋น ํ๋กํ์ ์ค์ ์ด ์ ์ฉ๋์ด ์คํ๋ผ์. ์์ ์ฝ์ฃ ? ๐
โ ๏ธ ์ฃผ์์ฌํญ: ํ๋กํ์ ์ฌ์ฉํ ๋๋ ๋ณด์์ ์ฃผ์ํด์ผ ํด์. ํนํ ์ด์ ํ๊ฒฝ์ ์ค์ํ ์ ๋ณด(DB ๋น๋ฐ๋ฒํธ ๊ฐ์ ๊ฒ๋ค)๋ ์ ๋ Git ๊ฐ์ ๋ฒ์ ๊ด๋ฆฌ ์์คํ ์ ์ฌ๋ฆฌ๋ฉด ์ ๋ผ์! ์ด๋ฐ ์ ๋ณด๋ ํ๊ฒฝ ๋ณ์๋ ๋ณ๋์ ์์ ํ ์ ์ฅ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ต๋๋ค.
์ฌ๊ธฐ์ ์ ๊น! ํน์ ์ด๋ฐ ๊ฐ๋ฐ ์ง์์ ๋ค๋ฅธ ์ฌ๋๋ค๊ณผ ๋๋๊ณ ์ถ์ผ์ ๊ฐ์? ๊ทธ๋ ๋ค๋ฉด ์ฌ๋ฅ๋ท์ ํ์ฉํด๋ณด๋ ๊ฑด ์ด๋จ๊น์? ์ฌ๋ฌ๋ถ์ Spring Boot ์ง์์ ๊ณต์ ํ๊ณ , ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ ๋ ธํ์ฐ๋ ๋ฐฐ์ธ ์ ์๋ ์ข์ ๊ธฐํ๊ฐ ๋ ๊ฑฐ์์! ๐ค
4. @Value์ @ConfigurationProperties ์ฌ์ฉํ๊ธฐ ๐ฏ
์, ์ด์ ์ค์ ํ์ผ์ ๋ง๋ค์์ผ๋ ์ด๊ฑธ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ์์๋ณผ๊น์? Spring Boot์์๋ @Value์ @ConfigurationProperties๋ผ๋ ๋ ๊ฐ์ง ์ฃผ์ ๋ฐฉ๋ฒ์ ์ ๊ณตํด์. ์ด ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ฐจ์ด์ ๊ณผ ์ฌ์ฉ๋ฒ์ ์์ธํ ์์๋ณด๊ฒ ์ต๋๋ค!
4.1 @Value ์ ๋ ธํ ์ด์ ์ฌ์ฉํ๊ธฐ ๐
@Value ์ ๋
ธํ
์ด์
์ ๊ฐ๋จํ๊ฒ ์ค์ ๊ฐ์ ์ฃผ์
๋ฐ์ ๋ ์ฌ์ฉํด์. ํน์ ํ๋์ ์ง์ ๊ฐ์ ์ฃผ์
ํ ์ ์์ฃ . ์ฌ์ฉ๋ฒ์ ์ด๋ ์ต๋๋ค:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class MyService {
@Value("${server.port}")
private int serverPort;
@Value("${spring.datasource.url}")
private String databaseUrl;
// ๋ฉ์๋๋ค...
}
์ด๋ ๊ฒ ํ๋ฉด application.properties ๋๋ application.yml์ ์ ์๋ server.port์ spring.datasource.url ๊ฐ์ด ๊ฐ๊ฐ serverPort์ databaseUrl ํ๋์ ์ฃผ์
๋ผ์.
@Value์ ์ฅ์ ์ ๊ฐ๋จํ๊ณ ์ง๊ด์ ์ด๋ผ๋ ๊ฑฐ์์. ํ์ง๋ง ์ฌ๋ฌ ๊ฐ์ ๊ด๋ จ๋ ์ค์ ์ ๋ฌถ์ด์ ๊ด๋ฆฌํ๊ธฐ๋ ์ข ๋ถํธํ์ฃ .
4.2 @ConfigurationProperties ์ฌ์ฉํ๊ธฐ ๐ฆ
@ConfigurationProperties๋ ์ฌ๋ฌ ์ค์ ์ ํ๋์ ํด๋์ค๋ก ๋ฌถ์ด์ ๊ด๋ฆฌํ ์ ์๊ฒ ํด์ค์. ํนํ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง ์ค์ ์ ๋ค๋ฃฐ ๋ ์์ฃผ ์ ์ฉํ๋ต๋๋ค.
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "myapp.datasource")
public class DatabaseProperties {
private String url;
private String username;
private String password;
// getter์ setter ๋ฉ์๋๋ค...
}
์ด๋ ๊ฒ ์ค์ ํ๊ณ application.yml์ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ๋ฉด:
myapp:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: user
password: pass
Spring Boot๊ฐ ์๋์ผ๋ก DatabaseProperties ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ฐ์ ์ฑ์์ค์. ์์ ํธํ์ฃ ? ๐
๐ @ConfigurationProperties์ ์ฅ์ :
- ๊ด๋ จ๋ ์ค์ ์ ํ๋์ ํด๋์ค๋ก ๋ฌถ์ ์ ์์ด์.
- ํ์ ์์ ์ฑ์ ๋ณด์ฅํด์. (์: int๋ก ์ ์ธ๋ ํ๋์ ๋ฌธ์์ด์ด ๋ค์ด์ค๋ฉด ์ค๋ฅ ๋ฐ์)
- IDE์ ์๋ ์์ฑ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ด์. (๋ฉํ๋ฐ์ดํฐ ํ๋ก์ธ์๋ฅผ ์ฌ์ฉํ๋ฉด)
4.3 @Value vs @ConfigurationProperties: ์ด๋ค ๊ฑธ ์ฌ์ฉํด์ผ ํ ๊น? ๐ค
๋ ๋ฐฉ๋ฒ ๋ค ์ฅ๋จ์ ์ด ์์ด์. ๊ฐ๋จํ ์ ๋ฆฌํด๋ณผ๊ฒ์:
- @Value: ๊ฐ๋จํ ์ค์ ๊ฐ ํ๋๋ฅผ ์ฃผ์ ๋ฐ์ ๋ ์ข์์. ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ง์ฃ .
- @ConfigurationProperties: ๊ด๋ จ๋ ์ฌ๋ฌ ์ค์ ์ ๋ฌถ์ด์ ๊ด๋ฆฌํ ๋, ๋๋ ๊ณ์ธต ๊ตฌ์กฐ๊ฐ ์๋ ๋ณต์กํ ์ค์ ์ ๋ค๋ฃฐ ๋ ์ข์์.
๊ฐ์ธ์ ์ธ ์๊ฒฌ์ ๋งํ์๋ฉด, ๊ฐ๋ฅํ๋ฉด @ConfigurationProperties๋ฅผ ์ฌ์ฉํ๋ ๊ฑธ ์ถ์ฒํด์. ์๋๊ณ ์? ๋์ค์ ์ค์ ์ด ๋ณต์กํด์ ธ๋ ์ฝ๊ฒ ๊ด๋ฆฌํ ์ ์๊ฑฐ๋ ์. ๊ทธ๋ฆฌ๊ณ ๋ฌด์๋ณด๋ค ํ์
์์ ์ฑ์ด ๋ณด์ฅ๋๋๊น ์ค์ํ ํ๋ฅ ์ด ์ค์ด๋ค์ฃ ! ๐
5. ํ๊ฒฝ ๋ณ์์ ์ปค๋งจ๋ ๋ผ์ธ ์ธ์ ์ฌ์ฉํ๊ธฐ ๐ฅ๏ธ
์, ์ด์ ์ค์ ํ์ผ ๋ง๊ณ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ์ค์ ์ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์์๋ณผ๊น์? Spring Boot๋ ์ ๋ง ๋๋ํด์ ํ๊ฒฝ ๋ณ์์ ์ปค๋งจ๋ ๋ผ์ธ ์ธ์๋ก๋ ์ค์ ์ ํ ์ ์์ด์. ์ด๊ฒ ์ ์ค์ํ๋๊ณ ์? ๋ณด์! ๋ฐ๋ก ๋ณด์ ๋๋ฌธ์ด์์! ๐
5.1 ํ๊ฒฝ ๋ณ์ ์ฌ์ฉํ๊ธฐ ๐
ํ๊ฒฝ ๋ณ์๋ ์ด์ ์ฒด์ ๋ ๋ฒจ์์ ์ค์ ํ๋ ๊ฐ์ด์์. ํนํ ๋ฏผ๊ฐํ ์ ๋ณด(์: ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋น๋ฐ๋ฒํธ)๋ฅผ ๊ด๋ฆฌํ ๋ ์์ฃผ ์ ์ฉํ์ฃ .
์๋ฅผ ๋ค์ด, ๋ฆฌ๋ ์ค๋ macOS์์๋ ์ด๋ ๊ฒ ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํ ์ ์์ด์:
export SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/mydb
export SPRING_DATASOURCE_USERNAME=root
export SPRING_DATASOURCE_PASSWORD=supersecret
์๋์ฐ์์๋ ์ด๋ ๊ฒ ํด์:
set SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/mydb
set SPRING_DATASOURCE_USERNAME=root
set SPRING_DATASOURCE_PASSWORD=supersecret
์ด๋ ๊ฒ ์ค์ ํ ํ๊ฒฝ ๋ณ์๋ Spring Boot๊ฐ ์๋์ผ๋ก ์ฝ์ด๋ค์ฌ์. ์ ๊ธฐํ์ฃ ? ๐ฒ
5.2 ์ปค๋งจ๋ ๋ผ์ธ ์ธ์ ์ฌ์ฉํ๊ธฐ โจ๏ธ
์ปค๋งจ๋ ๋ผ์ธ ์ธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ ๋ ์ง์ ์ค์ ๊ฐ์ ์ ๋ฌํ๋ ๋ฐฉ๋ฒ์ด์์. ์ด๋ ๊ฒ ์ฌ์ฉํ ์ ์์ฃ :
java -jar myapp.jar --server.port=8080 --spring.datasource.url=jdbc:mysql://localhost:3306/mydb
์ด ๋ฐฉ๋ฒ์ ํนํ Docker ์ปจํ ์ด๋๋ฅผ ์ฌ์ฉํ ๋ ์ ์ฉํด์. ์ปจํ ์ด๋๋ฅผ ์คํํ ๋๋ง๋ค ๋ค๋ฅธ ์ค์ ์ ์ ์ฉํ ์ ์๊ฑฐ๋ ์.
๐ ๋ณด์ ํ: ํ๊ฒฝ ๋ณ์๋ ์ปค๋งจ๋ ๋ผ์ธ ์ธ์๋ก ์ ๋ฌ๋ ๊ฐ์ ์ค์ ํ์ผ์ ๊ฐ๋ณด๋ค ์ฐ์ ์์๊ฐ ๋์์. ๋ฐ๋ผ์ ์ค์ํ ์ ๋ณด๋ ์ด ๋ฐฉ๋ฒ์ผ๋ก ์ ๋ฌํ๊ณ , ์ค์ ํ์ผ์๋ ๊ธฐ๋ณธ๊ฐ๋ง ๋ฃ์ด๋๋ ๊ฒ์ด ์ข๋ต๋๋ค!
5.3 ์ฐ์ ์์ ์ดํดํ๊ธฐ ๐
Spring Boot๋ ์ฌ๋ฌ ๊ณณ์์ ์ค์ ์ ์ฝ์ด์ฌ ์ ์์ด์. ๊ทธ๋ผ ๊ฐ์ ์ค์ ์ด ์ฌ๋ฌ ๊ณณ์ ์๋ค๋ฉด ์ด๋ค ๊ฐ์ ์ฌ์ฉํ ๊น์? ๋ฐ๋ก ์ฐ์ ์์์ ๋ฐ๋ผ ๊ฒฐ์ ๋ผ์!
๋๋ต์ ์ธ ์ฐ์ ์์๋ ์ด๋ ๋ต๋๋ค (๋์ ์์๋ถํฐ):
- ์ปค๋งจ๋ ๋ผ์ธ ์ธ์
- Java ์์คํ ํ๋กํผํฐ
- OS ํ๊ฒฝ ๋ณ์
- application.properties ๋๋ application.yml (์ธ๋ถ)
- application.properties ๋๋ application.yml (ํจํค์ง ๋ด๋ถ)
์ด ์ฐ์ ์์๋ฅผ ์ ์ดํดํ๊ณ ์์ผ๋ฉด, ์ค์ ๊ด๋ฆฌ๊ฐ ํ๊ฒฐ ์์ํด์ง ๊ฑฐ์์. ์๋ฅผ ๋ค์ด, ๊ฐ๋ฐ ํ๊ฒฝ์์๋ application-dev.yml์ ์ฌ์ฉํ๊ณ , ์ด์ ํ๊ฒฝ์์๋ ํ๊ฒฝ ๋ณ์๋ก ์ค์ ์ ๋ณด๋ฅผ ๋ฎ์ด์ฐ๋ ์์ผ๋ก ๊ด๋ฆฌํ ์ ์์ฃ .
์ฌ๊ธฐ์ ์ ๊น! ์ด๋ฐ ์ค์ ๊ด๋ฆฌ ๋ ธํ์ฐ๋ฅผ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค๊ณผ ๊ณต์ ํ๊ณ ์ถ์ง ์์ผ์ธ์? ์ฌ๋ฅ๋ท์์ ์ฌ๋ฌ๋ถ์ ์ง์์ ๋๋์ด๋ณด๋ ๊ฑด ์ด๋จ๊น์? ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์๊ฒ ๋์์ด ๋๋ฉด์, ์ฌ๋ฌ๋ถ๋ ์๋ก์ด ์ธ์ฌ์ดํธ๋ฅผ ์ป์ ์ ์์ ๊ฑฐ์์! ๐ก
6. ์ค์ ๊ฐ ์ํธํํ๊ธฐ ๐
์, ์ด์ ์ค์ ๊ด๋ฆฌ์ ๊ฝ์ด๋ผ๊ณ ํ ์ ์๋ ์ค์ ๊ฐ ์ํธํ์ ๋ํด ์์๋ณผ๊น์? ๋ณด์์ด ์ค์ํ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ํ์๋ผ๊ณ ํ ์ ์์ฃ !
6.1 ์ ์ค์ ๊ฐ์ ์ํธํํด์ผ ํ ๊น์? ๐ค
์ฌ๋ฌ๋ถ, ์์ํด๋ณด์ธ์. ์ฌ๋ฌ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์ ์ค์ ํ์ผ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋น๋ฐ๋ฒํธ, API ํค, ์ํธํ ํค ๋ฑ์ด ํ๋ฌธ์ผ๋ก ์ ํ์๋ค๋ฉด? ๐ฑ ๋๊ตฐ๊ฐ ์ด ํ์ผ์ ๋ณด๊ฒ ๋๋ค๋ฉด ๋์ฐธ์ฌ๊ฐ ์ผ์ด๋ ์ ์๊ฒ ์ฃ ?
๋ฐ๋ก ์ด๋ฐ ์ด์ ๋๋ฌธ์ ์ค์ํ ์ค์ ๊ฐ์ ๋ฐ๋์ ์ํธํํด์ผ ํด์. Spring Boot์์๋ ์ด๋ฅผ ์ํ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋๋ฐ, ๊ทธ ์ค ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋ ๋ฐฉ๋ฒ์ด ๋ฐ๋ก Jasypt(Java Simplified Encryption)์์.
6.2 Jasypt ์ค์ ํ๊ธฐ ๐ ๏ธ
Jasypt๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋จผ์ ์์กด์ฑ์ ์ถ๊ฐํด์ผ ํด์. build.gradle ํ์ผ์ ๋ค์ ๋ด์ฉ์ ์ถ๊ฐํด์ฃผ์ธ์:
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.3'
๊ทธ๋ฆฌ๊ณ application.yml ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ด Jasypt ์ค์ ์ ์ถ๊ฐํด์ค๋๋ค:
jasypt:
encryptor:
password: ${JASYPT_ENCRYPTOR_PASSWORD}
์ฌ๊ธฐ์ ${JASYPT_ENCRYPTOR_PASSWORD}๋ ํ๊ฒฝ ๋ณ์๋ก ์ค์ ํ ์ํธํ ํค์์. ์ด ํค๋ ์ ๋๋ก ์์ค ์ฝ๋๋ ์ค์ ํ์ผ์ ์ง์ ๋ฃ์ผ๋ฉด ์ ๋ผ์! ๊ผญ ํ๊ฒฝ ๋ณ์๋ก ๊ด๋ฆฌํด์ฃผ์ธ์.
6.3 ์ค์ ๊ฐ ์ํธํํ๊ธฐ ๐
์, ์ด์ ์ค์ํ ์ค์ ๊ฐ์ ์ํธํํด๋ณผ๊น์? Jasypt๋ ๋ช ๋ น์ค ๋๊ตฌ๋ฅผ ์ ๊ณตํ์ง๋ง, ๊ฐ๋จํ Java ์ฝ๋๋ก๋ ์ํธํํ ์ ์์ด์. ์๋ฅผ ๋ค์ด:
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
public class PasswordEncryptor {
public static void main(String[] args) {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword("yourEncryptionKey"); // ์ค์ ๋ก๋ ํ๊ฒฝ ๋ณ์์์ ๊ฐ์ ธ์์ผ ํด์!
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setProviderName("SunJCE");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
String plainText = "superSecretPassword";
String encryptedText = encryptor.encrypt(plainText);
System.out.println("Encrypted: " + encryptedText);
}
}
์ด๋ ๊ฒ ์ํธํ๋ ๊ฐ์ ์ป์ ์ ์์ด์. ์ด์ ์ด ๊ฐ์ ์ค์ ํ์ผ์ ๋ฃ์ ๋๋ ENC()๋ก ๊ฐ์ธ์ฃผ๋ฉด ๋ผ์:
spring:
datasource:
password: ENC(์ฌ๊ธฐ์ ์ํธํ๋ ๊ฐ์ ๋ฃ์ด์ฃผ์ธ์)
์ด๋ ๊ฒ ํ๋ฉด Spring Boot๊ฐ ์๋์ผ๋ก ์ด ๊ฐ์ ๋ณตํธํํด์ ์ฌ์ฉํด์. ์์ ์ ๊ธฐํ์ฃ ? ๐
๐ก Pro Tip: ์ํธํ ํค๋ ์ ๋๋ก ์์ค ์ฝ๋์ ํ๋์ฝ๋ฉํ๋ฉด ์ ๋ผ์! ์์ ์์ ๋ ์ค๋ช ์ ์ํ ๊ฒ์ผ ๋ฟ์ด์์. ์ค์ ๋ก๋ ํ๊ฒฝ ๋ณ์๋ ์์ ํ ํค ๊ด๋ฆฌ ์์คํ ์ ์ฌ์ฉํด์ผ ํด์.
6.4 ์ํธํ๋ ๊ฐ ์ฌ์ฉํ๊ธฐ ๐
์ํธํ๋ ๊ฐ์ ์ฌ์ฉํ ๋๋ ํน๋ณํ ํ ์ผ์ด ์์ด์. Spring Boot๊ฐ ์์์ ๋ณตํธํํด์ ์ฌ์ฉํ๊ฑฐ๋ ์. ์๋ฅผ ๋ค์ด:
@Value("${spring.datasource.password}")
private String databasePassword;
์ด๋ ๊ฒ ํ๋ฉด databasePassword ๋ณ์์๋ ๋ณตํธํ๋ ์ค์ ๋น๋ฐ๋ฒํธ๊ฐ ๋ค์ด๊ฐ์. ํธํ์ฃ ? ๐
์ํธํ๋ฅผ ์ฌ์ฉํ๋ฉด ์ค์ ํ์ผ์ ๋ฒ์ ๊ด ๋ฆฌ ์์คํ ์ ์์ ํ๊ฒ ์ฌ๋ฆด ์ ์๊ณ , ํ์๋ค๊ณผ ๊ณต์ ํ ๋๋ ๊ฑฑ์ ์ด ์์ด์ ธ์. ๋ฌผ๋ก , ์ํธํ ํค ์์ฒด๋ ์ ๋๋ก ๊ณต์ ํ๋ฉด ์ ๋๊ฒ ์ฃ ?
7. ์ค์ ๋ฆฌํ๋ ์ํ๊ธฐ ๐
์, ์ด์ ์ ๋ง ๊ณ ๊ธ ๊ธฐ์ ์ ์์๋ณผ ์ฐจ๋ก์์. ๋ฐ๋ก ๋ฐํ์์ ์ค์ ์ ๋ฆฌํ๋ ์ํ๋ ๋ฐฉ๋ฒ์ด์์. ์ด๊ฒ ๋ฌด์จ ๋ง์ด๋๊ณ ์? ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์์ํ์ง ์๊ณ ๋ ์ค์ ์ ๋ณ๊ฒฝํ ์ ์๋ค๋ ๊ฑฐ์์! ๐ฒ
7.1 @RefreshScope ์ฌ์ฉํ๊ธฐ ๐ฏ
Spring Cloud ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด @RefreshScope ์ ๋
ธํ
์ด์
์ ํตํด ํน์ ๋น์ ์ค์ ์ ๋์ ์ผ๋ก ๋ฆฌํ๋ ์ํ ์ ์์ด์. ๋จผ์ ์์กด์ฑ์ ์ถ๊ฐํด๋ณผ๊น์?
implementation 'org.springframework.cloud:spring-cloud-starter'
๊ทธ๋ฆฌ๊ณ ์ค์ ์ ๋ฆฌํ๋ ์ํ๊ณ ์ถ์ ๋น์ @RefreshScope๋ฅผ ๋ถ์ฌ์ฃผ์ธ์:
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@RefreshScope
@Component
public class DatabaseConfig {
@Value("${spring.datasource.url}")
private String url;
// getter, setter...
}
7.2 ์ค์ ๋ฆฌํ๋ ์ ์๋ํฌ์ธํธ ํ์ฑํํ๊ธฐ ๐
์ด์ ์ค์ ์ ๋ฆฌํ๋ ์ํ ์ ์๋ ์๋ํฌ์ธํธ๋ฅผ ํ์ฑํํด์ผ ํด์. application.yml์ ๋ค์ ๋ด์ฉ์ ์ถ๊ฐํด์ฃผ์ธ์:
management:
endpoints:
web:
exposure:
include: refresh
์ด๋ ๊ฒ ํ๋ฉด /actuator/refresh ์๋ํฌ์ธํธ๊ฐ ํ์ฑํ๋ผ์.
7.3 ์ค์ ๋ฆฌํ๋ ์ํ๊ธฐ ๐
์ด์ ์ค์ ์ ๋ณ๊ฒฝํ๊ณ ์ถ์ ๋๋ง๋ค ์ด ์๋ํฌ์ธํธ๋ก POST ์์ฒญ์ ๋ณด๋ด๋ฉด ๋ผ์:
curl -X POST http://localhost:8080/actuator/refresh
์ด๋ ๊ฒ ํ๋ฉด @RefreshScope๊ฐ ๋ถ์ ๋น๋ค์ ์ค์ ์ด ๋ชจ๋ ๋ฆฌํ๋ ์๋ผ์. ์์ ์ ๊ธฐํ์ฃ ? ๐
โ ๏ธ ์ฃผ์์ฌํญ: ์ด ๊ธฐ๋ฅ์ ๋งค์ฐ ๊ฐ๋ ฅํ์ง๋ง, ๋ณด์์ ์ฃผ์ํด์ผ ํด์. ๋๊ตฌ๋ ์ด ์๋ํฌ์ธํธ์ ์ ๊ทผํ ์ ์๋ค๋ฉด ํฐ ๋ฌธ์ ๊ฐ ๋ ์ ์์ฃ . ๋ฐ๋์ ์ ์ ํ ๋ณด์ ์ค์ ์ ํด์ฃผ์ธ์!
8. ๋ง์น๋ฉฐ: ์ค์ ๊ด๋ฆฌ์ ๋ฒ ์คํธ ํ๋ํฐ์ค ๐
์, ์ด์ Spring Boot์ Externalized Configuration์ ๋ํด ๊ฑฐ์ ๋ชจ๋ ๊ฒ์ ๋ฐฐ์ ์ด์! ๋ง์ง๋ง์ผ๋ก, ์ค์ ๊ด๋ฆฌ์ ๋ฒ ์คํธ ํ๋ํฐ์ค๋ฅผ ์ ๋ฆฌํด๋ณผ๊น์?
- ํ๊ฒฝ๋ณ ์ค์ ๋ถ๋ฆฌ: ๊ฐ๋ฐ, ํ ์คํธ, ์ด์ ํ๊ฒฝ์ ์ค์ ์ ๋ช ํํ ๋ถ๋ฆฌํ์ธ์.
- ๋ฏผ๊ฐํ ์ ๋ณด ๋ณดํธ: ๋น๋ฐ๋ฒํธ, API ํค ๋ฑ์ ๋ฐ๋์ ์ํธํํ๊ฑฐ๋ ํ๊ฒฝ ๋ณ์๋ก ๊ด๋ฆฌํ์ธ์.
- ๋ฒ์ ๊ด๋ฆฌ: ์ค์ ํ์ผ๋ ์์ค ์ฝ๋์ ํจ๊ป ๋ฒ์ ๊ด๋ฆฌํ์ธ์. ๋จ, ๋ฏผ๊ฐํ ์ ๋ณด๋ ์ ์ธ!
- ๋ฌธ์ํ: ๊ฐ ์ค์ ์ ์๋ฏธ์ ์ฌ์ฉ๋ฒ์ ๋ฌธ์๋ก ๋จ๊ธฐ์ธ์. ํ์๋ค์๊ฒ ํฐ ๋์์ด ๋ ๊ฑฐ์์.
- ์ ํจ์ฑ ๊ฒ์ฌ: ๊ฐ๋ฅํ๋ฉด ์ค์ ๊ฐ์ ์ ํจ์ฑ์ ๊ฒ์ฌํ๋ ๋ก์ง์ ์ถ๊ฐํ์ธ์.
- ๊ธฐ๋ณธ๊ฐ ์ ๊ณต: ๋ชจ๋ ์ค์ ์ ์ ์ ํ ๊ธฐ๋ณธ๊ฐ์ ์ ๊ณตํ์ธ์. ์ค์๋ก ์ค์ ์ ๋นผ๋จน์ด๋ ๋ฌธ์ ์๊ฒ!
- ๋ก๊น : ์ด๋ค ์ค์ ์ด ์ฌ์ฉ๋๊ณ ์๋์ง ๋ก๊ทธ๋ก ๋จ๊ธฐ์ธ์. ๋ฌธ์ ํด๊ฒฐ์ ํฐ ๋์์ด ๋ผ์.
์ด๋ ๊ฒ Spring Boot์ Externalized Configuration์ ๋ํด ๊น์ด ์๊ฒ ์์๋ดค์ด์. ์ด์ ์ฌ๋ฌ๋ถ์ ์ค์ ๊ด๋ฆฌ์ ๋ฌ์ธ์ด ๋์๋ต๋๋ค! ๐
๊ทธ๋ฐ๋ฐ ๋ง์ด์์, ์ด๋ ๊ฒ ๋ฐฐ์ด ์ง์์ ํผ์๋ง ์๊ณ ์๊ธฐ๋ ๋๋ฌด ์๊น์ง ์๋์? ์ฌ๋ฅ๋ท์์ ์ฌ๋ฌ๋ถ์ ์ง์์ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค๊ณผ ๋๋ ๋ณด๋ ๊ฑด ์ด๋จ๊น์? ์ฌ๋ฌ๋ถ์ ๊ฒฝํ๊ณผ ๋ ธํ์ฐ๋ ๋ค๋ฅธ ๋๊ตฐ๊ฐ์๊ฒ ํฐ ๋์์ด ๋ ์ ์์ด์. ๊ทธ๋ฆฌ๊ณ ๊ฐ๋ฅด์น๋ฉด์ ๋ฐฐ์ฐ๋ ๊ฒ๋ ๋ง๋ต๋๋ค! ๐ค
Spring Boot๋ก ๊ฐ๋ฐํ๋ฉด์ ๊ถ๊ธํ ์ ์ด ์๊ธฐ๋ฉด ์ธ์ ๋ ๋ฌผ์ด๋ณด์ธ์. ํจ๊ป ์ฑ์ฅํ๋ ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ๋ฅผ ๋ง๋ค์ด๊ฐ์! ํ์ดํ ! ๐ช
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.