(Spring) resources 경로 문제
[!info] Spring에 대한 내용과 Jar에 대한 내용이 섞여있어서… 적당히 분리해서 이해해야 함.
- resources 이하에 있는 파일들(.yml, .properties, 인증서 등)은 컴파일 타임에 CLASS_PATH로 이동하여 함께 포함되어 빌드된다.
- spring의 경우 target/classes에 위치.
- jar로 컴파일 하도록 했으면 .jar에 포함된다.
- 그래서 리소스를 ClassPath 사용해서 제대로 불러왔다면
build/resources
를 통째로 날려도 잘 실행 된다. - yml 등은 알아서 jar 내에 있는 것을 사용한다.
- 다만 소스코드 내에서 ClassPath를 쓰지 않고 그냥 File에 접근하게 되면 , 실제 파일시스템에 있는 해당 경로로 가서 해당 파일이 있는지를 찾는다.
- 이 때 해당 파일이 지워져있다면? 당연히 못찾는다.
- 경로를 상대경로로 지정한 경우? 상대경로는 java -jar 명령어를 실행하는 위치에 따라 결정되기 때문에, 어디서 명령어를 실행하느냐에 따라 파일을 못찾을 수 있다.
1
2
3
FileInputStream(filePath) // --- X / 실제 파일시스템에서 파일을 찾는다
FileSystemResource(filePath)
ClassPathResource(classPath).inputStream // --- O / jar 내에서 찾는다
- 위와 같이 jar 내에서 가져오도록 하는 것이 좋다.
1
2
3
val resourceStream = KakaoConfig::class.java.getResourceAsStream ("/secrets/kakao_config.properties") ? : throw FileNotFoundException()
val properties = Properties().apply { load(resourceStream) }
resourceStream.close()
절대 경로로 변환하기
- ClassPathResource를 사용하 면, 앞에
classpath:
prefix를 resolve하는게 아니라 그냥 알아서 classpath 내에서 찾는다. - 근데 경우에 따라
classpath:
prefix를 사용하는 경우와 사용하지 않는 경우를 모두 커버하고 싶을 수 있음. - 그래서 그냥 ResourceUtils 사용하는 편이 좋다.
1
2
3
4
5
6
7
8
private String getAbsolutePath(String path) {
try {
return ResourceUtils.getFile(path).getAbsolutePath();
} catch (FileNotFoundException e) {
log.error("### path not found exception");
throw new RuntimeException(e);
}
}
전역 token은 resources에서? 파일시스템에서?
[!tip] 모든 상황을 만족하는 최선의 전략은 없고, 상황 따라 선택하면 됨.
그러나 보통 여러 repo에서 전역으로 사용하는 토큰은, 각 소스 레포지토리의 resources 디렉토리에 각각 두면 관리도 힘들고 변경이 발생했을 때 다 찾아가서 바꿔주어야 한다.
그래서 중앙의 key 저장소를 참조하도록 하는 것이 베스트인데,
이걸 따로 구축하기 귀찮은 경우 임시로 파일시스템에서 읽어오도록 (e.g., ~/secrets) 하는 것이 낫다.
1
2
3
val resourceStream = FileInputStream("${System.getProperty("user.home")}${File.separator}secrets${File.separator}line_token.properties")
val properties = Properties().apply{ load(resourceStream) }
resourceStream.close()
참고로
System.getProperty("user.dir")
는 jar 명령어를 실행했을 때 쉘의 디렉토리 위치를 의미한다.
This post is licensed under CC BY 4.0 by the author.