이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.
기초개념 › Spring
설정 파일은 무엇이고, 코드에 적는 것과 무엇이 다른가
설정 파일은 코드와 따로 둔 글 파일입니다. 스프링 부트에서는 application.properties라는 이름이고, 안에는 "이름=값" 줄을 적습니다(shop.name=kim-shop). 포트 번호나 접속 주소처럼 환경마다 달라지는 값을 코드에 직접 적으면 값이 바뀔 때마다 코드를 고쳐 다시 컴파일해야 하므로, 값은 이 파일에 두고 코드는 이름만 적습니다. 코드에서 값이 필요한 필드 위에 @Value("${이름}") 줄을 적으면, 스프링이 객체를 만들 때 설정 파일에서 그 이름의 값을 찾아 필드에 넣어 줍니다. ${이름:기본값} 꼴로 : 뒤에 기본값을 적어 두면 설정에 그 이름이 없을 때 그 값을 씁니다. 이 실습은 설정 파일의 shop.name 줄을 바꾸거나 지우고, @Value에 기본값을 붙이거나 떼면서 java 명령으로 프로그램을 실행해, name 필드에 어떤 값이 들어오는지, 프로그램이 제대로 시작하는지를 봅니다.
실행으로 대조 · 스프링 부트 4.1.1에서 여섯 가지 조합을 조합마다 소스를 컴파일해 자식 java 프로세스로 실행하고, 표준 출력·종료 코드·예외를 프로세스 밖에서 관찰해 대조
# application.properties
# 설정: 이름=값 꼴로 코드 밖에 적는 값
shop.name=kim-shop
@Component
class ShopInfo {
// 받기: 설정에서 shop.name 값을 찾아 name에 넣는다
@Value("${shop.name}")
String name;
}
@SpringBootApplication
public class App {
public static void main(String[] args) {
// 스프링을 시작한다. ctx는 스프링이 만든 객체를 보관한 곳이다
ApplicationContext ctx = SpringApplication.run(App.class, args);
ShopInfo info = ctx.getBean(ShopInfo.class);
System.out.println(info.name);
}
}
스프링 부트 4.1.1(스프링 프레임워크 7.0.9)을 JDK 21.0.12.1에서 실행한 결과입니다. 여섯 가지 조합을 모두, 화면의 코드와 같은 구조의 소스(패키지 app의 ShopInfo와 App, 그리고 클래스 파일과 같은 폴더에 둔 application.properties)를 컴파일하고 java 명령으로 app.App의 main 메서드부터 새 프로세스로 실행해 대조했습니다. 대조한 것은 결과 표의 세 항목입니다. name에 들어온 값은 프로세스가 표준 출력에 찍은 글로, 시작 성공 여부는 종료 코드(0과 1)와 표준 출력으로, 오류는 표준 오류에 나온 예외의 이름과 메시지로 정했습니다. 설정 파일을 지운 조합에서는 파일에서 shop.name 줄과 바로 위 설명 줄만 지우고 맨 위의 # application.properties 줄은 남겼습니다. 단계 문장이 기대는 사실도 실행으로 확인했습니다. 설정 파일을 둔 조합에서 스프링이 클래스패스의 application.properties를 설정 출처로 읽고(Config resource class path resource [application.properties]) 그 안의 shop.name 값이 스프링의 Environment에 들어 있는 것, SpringApplication.run이 끝났을 때 ShopInfo 객체가 이미 만들어져 name 필드에 값이 들어 있는 것, 우리 소스에 new ShopInfo()나 name에 값을 넣는 줄이 없는 것, shop.name 줄이 없고 기본값도 없을 때 예외(BeanCreationException, 원인은 PlaceholderResolutionException의 Could not resolve placeholder 'shop.name' in value "${shop.name}")가 SpringApplication.run 줄에서 나와 main이 다음 줄에 가지 못하고 종료 코드 1로 끝나며 표준 출력에 아무것도 찍히지 않는 것, 같은 컴파일 결과(ShopInfo.class 파일과 App.class 파일의 해시가 같음)에서 application.properties만 kim-shop에서 lee-shop으로 고쳐 다시 실행하면 컴파일 없이 lee-shop이 나오는 것입니다. shop.name 줄을 지우고 기본값을 적은 조합에서는 파일에 이름=값 줄이 하나도 없어 스프링의 설정 출처 목록에 application.properties가 오르지 않는 것을 관찰했습니다. 단계 문장은 그 사실을 "설정 목록에 shop.name 이름이 없다"까지만 말합니다. 클래스패스는 라이브러리 폴더 전체가 아니라 spring-boot-starter가 들여오는 21개 jar만 줬고(스프링 부트 기초개념 실습과 같은 목록, 웹 라이브러리 없음), 자식 프로세스의 작업 폴더는 빈 임시 폴더로 했습니다(스프링 부트는 작업 폴더의 application.properties와 config 폴더도 읽기 때문입니다). 환경 변수 중 SPRING_과 SHOP_으로 시작하는 것은 자식 프로세스에서 뺐습니다. 문서가 정한 것은 스프링 부트 문서 Externalized Configuration 절(application.properties를 시작할 때 클래스패스 맨 위, 클래스패스의 /config 패키지, 현재 폴더, 현재 폴더의 config 폴더에서 찾아 읽는다는 것, 같은 코드를 환경마다 다르게 쓰려고 설정을 코드 밖에 둔다는 것, ${이름:기본값}에서 : 뒤가 기본값이라는 것)과 스프링 프레임워크 문서 Using @Value 절(@Value("${...}")로 외부 설정값을 넣는다는 것, 기본값 문법, 스프링 부트가 application.properties의 값을 읽는 PropertySourcesPlaceholderConfigurer를 기본으로 등록한다는 것, 이 설정자가 있으면 ${} 자리를 풀지 못할 때 초기화가 실패한다는 것)입니다. 스프링 프레임워크만 쓰고 이 설정자를 두지 않으면 풀지 못한 ${shop.name} 글자가 값으로 그대로 들어간다고 문서에 적혀 있지만, 이 실습은 스프링 부트에서만 실행했습니다. 값이 없을 때 BeanCreationException과 PlaceholderResolutionException이 나온다는 것은 문서가 정한 것이 아니라 이 버전에서 관찰한 동작입니다. 화면의 코드는 package와 import 줄을 줄였고, ShopInfo와 App이 같은 패키지에 있다고 가정했습니다. 두 클래스는 실제로는 파일이 따로이고, application.properties도 보통은 src/main/resources에 두며 빌드가 클래스 파일 옆으로 복사합니다(여기서는 직접 그 폴더에 두었습니다). 이 실습이 다루지 않는 것은 application.yml, 여러 곳에 같은 이름이 있을 때의 우선순위, 환경 변수와 실행 인자로 값을 바꾸는 것, 프로파일별 파일, @ConfigurationProperties입니다. 우선순위는 "세부 동작 실습: 설정 우선순위"에서, 설정을 보고 스프링 부트가 알아서 빈을 만드는 일은 "세부 동작 실습: 스프링 부트 자동 설정"에서 다룹니다.
줄을 그은 곳은 처음 코드에서 지운 것이고, 색을 칠한 곳은 새로 쓴 것입니다.