본문 바로가기

개발/Java & Spring

[Spring boot] 하나의 클래스로 properties 관리하여 사용하기!

스프링에서는 다른 환경에서 같은 코드로 Application을 실행하기 위해 외부설정을 해준다.

즉, server port나 user 정보를 비즈니스 로직과 분리시켜 외부로 빼고, 불러다 쓴다는 것이다.

 

이때 설정 값은 application.yml 또는 application.properties 에 작성하게 되는데, 내가 기존에 자주 쓰던 방법은 아래와 같다

 

application.properties

user.name=lemon
user.id=a1010100z
user.pass_word=12345678
user.code=${random.int(0,100)}
user.comment= Hi I'm ${user.name}

(여기서 살짝 미리 정의된 random과 먼저 정의된 값을 재사용하는 방법을 한번 익혀본다.)

 

 

이를 사용하는 이름은 Controller..지만 Runner 클래스

 

TestController.java

package com.edu.app.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import com.edu.app.component.UserProperty;

@Component
public class TestController implements ApplicationRunner{
	
	@Value("${user.name}")
	private String name;
	@Value("${user.id}")
	private String id;
	@Value("${user.pass_word}")
	private String password;
	@Value("${user.code}")
	private String code;
	@Value("${user.comment}")
	private String comment;

	@Override
	public void run(ApplicationArguments args) throws Exception {
		System.out.println("username:"+name);
		System.out.println("userId:"+id);
		System.out.println("userPassword:"+password);
		System.out.println("userCode:"+code);
		System.out.println("userComment:"+comment);		
	}
	
}

이렇게 해도 실행은된다.

 

하지만 이런 경우 일단 저 @Value 부분이 너무 길어지면 보기 싫고, 오타날 가능성도 매우 높기 때문에 사용성이 크게 좋지는 않다.

 

그리고 또, 당장 properties파일의 user.pass_word를 user.password로 바꾼 뒤 재실행하면 바로 런타임에러가 나버린다.

 

 

 

또 다른 외부설정 방법 중 하나는

하나의 Component로 설정파일을 관리하고, 문법에 조금 더 유연하게 다룰 수 있는 방법이다.

application.properties는 처음 썼던 그대로 유지한다.

그 다음, 이에 해당하는 Component 클래스를 하나 생성해준다.

 

 

 

UserProperty.java

package com.edu.app.component;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("user")//user계층의 모든 설정을 매핑한다. 
public class UserProperty {
	private String name;
	private String id;
	private String password;
	private int code;
	private String comment;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public int getCode() {
		return code;
	}
	public void setCode(int code) {
		this.code = code;
	}
	public String getComment() {
		return comment;
	}
	public void setComment(String comment) {
		this.comment = comment;
	}
}

상단의 @ConfigurationProperties("user")를 통해 설정파일과 매핑시킬 수 있다.

이제 TestController코드도 좀 수정해본다.

 

 

TestController.java

package com.edu.app.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import com.edu.app.component.UserProperty;

@Component
public class TestController implements ApplicationRunner{
	
	@Autowired
	private UserProperty userProperties;
	@Override
	public void run(ApplicationArguments args) throws Exception {
		System.out.println("username:"+userProperties.getName());
		System.out.println("userId:"+userProperties.getId());
		System.out.println("userPassword:"+userProperties.getPassword());
		System.out.println("userCode:"+userProperties.getCode());
		System.out.println("userComment:"+userProperties.getComment());
		
		
	}
}

아까보다 훨씬 더 깔끔해진 코드를 볼 수 있다.

사전에 정의한 Component 클래스만 신경쓰면 되기 때문에 오타도 고치기 수월하다.

 

spring boot를 실행하면 역시나 정상적으로 동작하는 것을 알 수 있다.

아까 위에서, "하나의 Component로 설정파일을 관리하고, 문법에 조금 더 유연하게 다룰 수 있는 방법이다."라는 말을 언급했는데,

 

확인하기 위해 properties 파일의 user.password를 user.pass-word로, 또 user.pass_word로, 또, user.passWord로도 바꿔보고 실행해보자.

 

 

모두 정상적으로 실행되는 것을 확인할 수 있다.

이는 공식 문서에서 'relaxed binding'이라고 칭한다.(하단 표 참고)

 

Table 24.1. relaxed binding

acme.my-project.person.first-name Kebab case, which is recommended for use in .properties and .yml files.
acme.myProject.person.firstName Standard camel case syntax.
acme.my_project.person.first_name Underscore notation, which is an alternative format for use in .properties and .yml files.
ACME_MYPROJECT_PERSON_FIRSTNAME Upper case format, which is recommended when using system environment variables.

 

 

또한 ${random.int(0,100)} 이 값은 자동적으로 int형에 바인딩 시켜주기도 한다.

 

하나의 properties 파일은 여러군데에서 쓰일 수 있기 때문에 하나의 Component 클래스로 관리해주는 것이 더 용이할 것 같다.

이외에도 다양한 외부 설정 방식은

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html 이곳에서 확인할 수 있다.