<청춘> 격정적으로 사는 것

밤을 새고 공부한 다음 날 새벽에 느꼈던 생생한 환희와 야생적인 즐거움을 잊을 수 없다

BOOK REVIEW/실전 스프링 부트 워크북

[실전 스프링 부트 워크북] 스프링부트 애플리케이션 구성 알아보기 / 스프링 부트 프로젝트 따라하기

수학도 2021. 8. 14. 17:34

프로퍼티 설정 예

간단한 프로젝트를 만들어 애플리케이션 구성을 자세히 살펴보자.


 

1. Spring Starter Project

 

File > New > Other

 

Spring Boot > Spring Starter Project

 

아래와 같이 Name, Type, Packaging 등을 입력하고 Next

 

스프링 부트 의존체는 넣지 않고 Finish

 

 

2. 스프링 부트 : 구성 프로퍼티 재정의

스프링 부트는 다음 순서대로 구성 프로퍼티를 재정의한다.

 

  1. 실행 명령어와 함께 전달한 인자
  2. SPRING_APPLICATION_JSON
  3. JNDI (java:comp/env)
  4. System.getProperties()
  5. OS 환경변수
  6. RandomValuePropertySource(random.*)
  7. JAR 패키지 외부의 프로파일 관련 구성 (application - {프로파일명}.jar)
  8. JAR 패키지 내부의 프로파일 관련 구성 (application - {프로파일명}.jar)
  9. JAR 패키지 외부의 애플리케이션 프로퍼티 (application.properties)
  10. JAR 패키지 내부의 애플리케이션 프로퍼티 (application.properties)
  11. @PropertySource
  12. SpringApplication.setDefaultProperties

 

JAR 패키지 외부 / 내부 ?

어떤 앱이 자체 application.properties를 지닌 JAR 라이브러리를 의존체로 사용한다면, 앱쪽 application.properties 파일을 '외부', JAR 라이브러리 안에 선언된 application.properties 파일을 '내부'라고 한다. 그리고 '외부'가 항상 '내부'보다 우선 적용된다.

 

 

예를 들어보자.

3. 명령행 인자

 

프로젝트의 메인 클래스를 다음과 같이 수정하자.

스프링은 @Value("${server.ip}") 코드를 만나면 server.ip 프로퍼티와 그 값을 위에서 열거한 우선순위 규칙에 따라 찾는다.

 

 

먼저 패키징(실행 가능한 JAR파일 생성)한 다음에 실행하면, (스프링 부트 CLI 이용)

  • JAR파일에 server.ip = 192.168.12.1 로 설정하는 과정
  • $ ./mvnw package -DskipTests = true
    $ java -jar target/spring-boot-config-0.0.1-SNAPSHOT.jar --server.ip = 192.168.12.1

 

콘솔 창에 다음과 같이 나타난다. 

 

 

다음엔, 서버 IP를 앱의 application.properties 파일에 설정해보자.

 

이름이 똑같은 인자를 명령행에서 전달하면 application.properties 파일보다 우선 적용된다. 

앱을 실행해보면, 콘솔 창에 다음과 같이 나타난다.

 

 

마지막으로, 운영체제의 환경 변수를 추가해서 참조해보자.

$ SEVER_IP 192.168.150.46 /mvnw spring-boot:run

 

앱을 실행해보면, 콘솔 창에 다음과 같이 나타난다.

 

스프링 부트는 환경 변수 SERVER_IP가 server.ip 프로퍼티에 해당한다는 걸 어떻게 알았을까?

4. 느슨한 바인딩

 

스프링 부트는 바인딩을 느슨하게 처리한다.

프로퍼티 설명
message.destinationName 표준 카멜 표기법
message.destination-name 대시(-) 사용, application.properties와 YAML 파일의 권장 표기법
MESSAGE_DESTINATION_NAME 대문자 사용, OS 환경 변수의 권장 표기법

 

위에서 server.ip를 SERVER_IP로 인식할 수 있던 것도 이 규칙 덕분이고, 느슨한 바인딩 덕분에 이름 충돌 문제도 예방할 수 있다.

 

 

5. 경로와 이름 변경

스프링 부트는 application.properties 또는 YAML 파일을 다음 순서대로 찾는다.

  1. 현재 폴더 하위의 /config 폴더
  2. 현재 폴더
  3. 클래스패스 /config 패키지
  4. 클래스패스 루트

 

① 우선 클래스패스 루트 (src/main/resources)에 application.properties 파일이 있는지 확인한다.

② 있다면, 현재 폴더 밑에 /config 폴더를 만들고 application.properties 파일을 새로 추가하고, server.ip = 127.0.0.1로 설정해준다.

 

 

  • 그럼 현재 src/main/resource/application.properties 파일에는 server.ip가 192.168.23.4로 설정되어 있고
  • /config/application.properties 파일에는 server.ip가 127.0.0.1로 설정되어 있는 상태이다.

③ 앱을 실행하면 콘솔 창은 다음과 같다.

즉, 클래스패스 보다 현재 폴더 하위의 /config 폴더에서 먼저 application.properties 파일을 찾는 것을 알 수 있다.

 

 

 

6. 프로파일 켜기

 

스프링 프레임워크는 프로파일에 따라 커스텀 프로퍼티와 빈을 생성할 수 있도록 했다. 개발자는 그냥 클래스를 테스트할 때 @ActiveProfiles 애너테이션에 액티브 프로파일을 지정하거나 현재 환경에서 setActiveProfiles 메서드로 액티브 프로파일을 바꾸면 된다. SPRING_PROFILES_ACTIVE 환경 변수 또는 spring.profiles.active라는 프로퍼티를 이용해도 된다.

 

application-{프로파일명}.properties 평식으로 이름을 붙인 프로퍼티 파일을 이용하는 방법도 있다.

① 하위폴더 /config에 application-prod.properties 파일을 만들고 그 안에 server.ip=http://my-remote.server.com 를 작성한다.

application-prod.properties

② 클래스패스 루트 (src/main/resources)에 application.properties 파일에 spring.profiles.active = prod 프로퍼티를 설정한다.

application.properties

  • 그럼 현재 src/main/resource/application.properties 파일에는 server.ip가 192.168.23.4로 설정되어 있고
  • /config/application-prod.properties 파일에는 server.ip가 http://my-remote.server.com으로 설정되어 있는 상태이다.

③ 앱을 실행하면 콘솔 창은 다음과 같다.

The following profiles are active: prod 에서 액티브 프로파일이 prod이고, 따라서 application-prod.properties 파일의 프로퍼티 값으로 '> 서버 IP: http://my-remote.server.com이 이 출력된다.

 

7. 커스텀 프로퍼티 접두어

스프링 부트에서는 개발자가 직접 커스텀 프로퍼티 접두어를 붙여 쓸 수 있다. 자바 클래스에 해당 프로퍼티를 멤버 변수로 선언하고 @ConfigurationProperties 애너테이션을 붙인 다음 getter와 setter를 추가하면 된다.

 

7-1. 우선, spring-boot-configuration-processor 의존체를 폼(pom.xml) 파일에 추가하자.

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>

이 의존체를 추가하면 편집기가 프로퍼티 코드의 자동완성 기능을 지원해서 편리하다.

 

 

7-2.  클래스패스 루트 (src/main/resources)에 application.properties 파일을 다음과 같이 수정한다.

server.ip = 192.168.3.5

myapp.server-ip = 192.168.34.56
myapp.name = My Config App
myapp.description = just code
  • server.ip는 원래 존재하는 프로퍼티(property)이다.
  • 'myapp'이라는 접두어로 추가된 커스텀 프로퍼티를 선언했다. - 개발자가 마음대로 만든 프로퍼티

 

 

7-3. 이 커스텀 프로퍼티를 사용하기 위해 메인 애플리케이션 코드를 다음과 같이 수정한다.

package com.apress.spring;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class SpringBootConfigApplication {

	private static Logger log = LoggerFactory.getLogger(SpringBootConfigApplication.class);
	
	public static void main(String[] args) {
		SpringApplication.run(SpringBootConfigApplication.class, args);
	}

	@Value("${myapp.server-ip}")
	String serverIp;
	
	@Autowired
	MyAppProperties props;
	
	@Bean
	CommandLineRunner values() {
		return args -> {
			log.info(" > 서버 IP: " + serverIp);
			log.info(" > 애플리케이션명: " + props.getName());
			log.info(" > 애플리케이션 정보: " + props.getDescription());
		};
	}
	
	@Component
	@ConfigurationProperties(prefix="myapp")
	public static class MyAppProperties {
		private String name;
		private String description;
		private String serverIp;
		
		public String getName() {
			return name;
		}
		
		public void setName(String name) {
			this.name = name;
		}
		
		public String getDescription() {
			return description;
		}
		
		public void setDescription(String description) {
			this.description = description;
		}
		
		public String getSeverIp() {
			return serverIp;
		}
		
		public void setServerIp(String ServerIp) {
			this.serverIp = serverIp;
		}

		
	}
	
}

@Value("${myapp.server-ip}")

myapp.server-ip에 해당하는 프로퍼티 값 192.168.34.56을 멤버 변수 serverIp에 주입한다.

 

@Autowired MyAppProperties props

MyAppProperties 타입의 인스턴스를 자동 연결한다.

 

@Component

스프링 빈 클래스임을 표시하는 애너테이션

 

@ConfigurationProperties(prefix="myapp")

@ConfigurationProperties는 이 MyAppProperties 클래스가 application.properties 파일에 정의된 모든 프로퍼티 앞에 접두어 myapp을 붙였다고 스프링 부트에 알리는 애너테이션이다. 그래서 myapp.serverIp( = myapp.server-ip), myapp.name, myapp.description 프로퍼티를 올바르게 인식한다.

 

props.getName()

props는 MyAppProperties 타입의 인스턴스인데, MyAppProperties 클래스는 @ConfigurationProperties(prefix="myapp") 애너테이션이 붙어있기 때문에 application.properties 파일에서 myapp접두어를 붙인 프로퍼티를 찾아온다. 즉, props.getName()은 application.properties 파일에서 myapp.name값인 "My Config App"을 얻어온다.

 

 

7-4. 앱을 실행하면 콘솔 창은 다음과 같다.