티스토리 뷰

반응형

Spring & Spring boot로 웹 어플리케이션을 만들어 보신분 들이라면 application.properties 파일을 보신적이 있나요?


properties 파일안에 db connection 정보나 file path 등등 여러가지 속성들을 기재해서 많이 사용하시죠?


저 또한 예전부터 properties 파일에 여러가지를 기재해서 사용을 많이 했습니다.


오늘은 이 properties 파일을 외부로 내보내서 여러가지 properties 파일을 관리를 하는 작업에 대해 작성을 하려고 합니다.


properties를 왜 외부로 빼서 관리를 하려는 것인가?


이유는 간단합니다. 어플리케이션을 만든 후 jar나 war로 빌드 후 (jar를 이용합시다!) 서버에 배포 후에 갑작스럽게 테스트를 하거나 다른 작업을 할 때 소스는 변경사항이 없으나 다른 db를 잠시 바라보고 싶을 때 어떻게 하시나요? class path 안에 있는 properties 파일을 변경 후 다시 빌드를 해야할 까요?


아니죠 properties 파일을 외부로 빼서 경로만 바꿔주고 실행시키면 간단합니다!


Spring doc 에서도 Externalized Configuration이라는 페이지가 있는데 한번 참고 해보세요.



사실 이게 정말 간단하고 쉬운 작업인데 제가 삽질을 많이해서 다른 분들은 삽질 하시지 말라고 작성 합니다...


일단 spring boot에서 properties 파일을 읽는 방법은 다양합니다.


1. @Value 어노테이션 사용하기

2. Environment 클래스 사용하기


그리고 spring doc에서 properties 적용 우선순위는 다음과 같습니다.


  1. file:./custom-config/
  2. classpath:custom-config/
  3. file:./config/
  4. file:./
  5. classpath:/config/
  6. classpath:/

그리고 jar command 에서 spring boot에서 외부의 properties 파일을 불러오는 option은 다음과 같은 방법 들이 있습니다.


1. spring.config.name

$ java -jar myproject.jar --spring.config.name=myproject

2. spring.config.location

$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties


저는 2번의 방법을 이용해서 외부의 properties 파일을 가져오려고 했습니다.


하지만 결론은 이 방법이 안되서 계속 삽질을 한 거였습니다 ㅠㅠ

왜 안되나 계속 찾다가 spring boot의 actuator도 사용해보고 하다가 결국에는 찾았습니다.


제가 기본의 spring mvc 프로젝트를 spring boot 프로젝트로 옮기며 rest api로 만드는 작업을 했는데

기존의 spring mvc 프로젝트를 만든 사람이 java.util.properties를 이용해 초기화 블럭을 이용해 사용을 해서 spring.config.location이 안먹혔습니다.



    static {
        loadProperties(); // 초기화 블럭 때문에 --spring.config.location이 안먹힘
} synchronized static private void loadProperties() { InputStream fis = null; try{ properties = new Properties(); fis = PropertiesService.class.getClassLoader().getResourceAsStream("application.properties");
properties.load(fis); }catch(FileNotFoundException fne){ debug(fne); }catch(IOException ioe){ debug(ioe); }catch(Exception e){ debug(e); }finally{ try { if (fis != null) { fis.close(); } else { fis = PropertiesService.class.getClassLoader().getResourceAsStream("application.properties"); properties.load(fis); fis.close(); } } catch (Exception ex) { //ex.printStackTrace(); logger.info("IGNORED: " + ex.getMessage()); } } }

그래서 이 것을 어떻게 해결해야 하나 계속 고민하다가 

결국에는 System.property를 이용해서 강제적으로 위치를 바꿔주기로 했습니다. 

    static {
        loadProperties();
    }
    
    synchronized static private void loadProperties() {
    	InputStream fis = null;
		try{
			properties = new Properties();
                        // 여기 고침
			fis = new FileInputStream(System.getProperty("spring_config_location").replaceAll("\\\\","/"));
			properties.load(fis);
		}catch(FileNotFoundException fne){
			debug(fne);
		}catch(IOException ioe){
			debug(ioe);
		}catch(Exception e){
			debug(e);
		}finally{
			try {
				if (fis != null) { fis.close(); } 
				else {
					fis = PropertiesService.class.getClassLoader().getResourceAsStream("application.properties");
					properties.load(fis);
					fis.close();
				}
			} catch (Exception ex) {
				//ex.printStackTrace();
				logger.info("IGNORED: " + ex.getMessage());
			}
		}
    }


그리고 --spring.config.location을 이용했다면 자동으로 그 위치를 참조했을 텐데 사용하던 코드 때문에 제가 직접 main이 실행되기 전에 강제적으로 위치를 지정해 줘야 했습니다.


import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy
public class RestWebApplication {
	
	public static void main(String[] args) {
//             기존의 spring boot 프로젝트
//		SpringApplication.run(RestWebApplication.class, args);
		
		String location;                 
		if (System.getProperty("spring_config_location") != null) {
			location = System.getProperty("spring_config_location").replaceAll("\\\\","/");			
		}  else {
			location = "classpath:/application.properties";
		};
		
		new SpringApplicationBuilder(KapRestWebApplication.class)
		.properties(
				"spring.config.location=" +
				"classpath:/application.properties" +
				", file:" + location
				).run(args);				
	}
}


제가 강제적으로 이렇게 만들었는데 그럼 어떻게 실행을 해야 하나????

java VM Arguments 에서 custom argumets를 주는 법을 아시나요? 바로 -Dcustom_arg 해서 앞에 

-D 를 붙여주는 겁니다.


그리고 저는 linux에서 실행 시키기 위해 다음과 같은 sh 파일을 만들었습니다.

#!/bin/sh
classpath=$(cd "$(dirname "$0")" && pwd)

FILEPATH=${classpath}'/RestWeb.jar'

if [ "$1" = "dev" ] || [ "$1" = "real" ] || [ "$1" = "test" ]; then
	config=''${classpath}'/'$1'/application.properties'
else
	config='classpath:/application.properties'
fi

# echo java -Dspring_config_location=${config} -jar ${FILEPATH} --spring.config.location=${config}
# java -Dspring_config_location=${config} -jar ${FILEPATH} --spring.config.location=${config}
nohup java -Dspring_config_location=${config} -jar ${FILEPATH} >> /dev/null 2>&1 &


개인이 새로 만드는게 아니라 이런식으로 만들 때 이러한 경우가 생길 수도 있었네요.

이러한 삽질을 한 경험으로 인해 한 층 더 성장한 느낌을 받았습니다!





출처 및 참고


https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html


https://araikuma.tistory.com/42


https://kingbbode.tistory.com/39


반응형

'BackEnd > Java' 카테고리의 다른 글

Spring boot Redis 사용하기  (3) 2019.03.12
Spring boot jwt token 사용하기  (5) 2019.03.05
nginx  (0) 2019.02.27
spring boot HikariCP  (1) 2019.01.06
openjdk 설치하기  (0) 2018.12.16
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함