[Spring] Resource 추상화
Spring은 java.net.URL을 org.springframework.core.io.Resource로 감싸서 추상화한 클래스를 제공한다.
어플리케이션에서 사용하는 리소스 자체를 추상화 한것인데 spring에서 이를 추상화한 이유는 다음과 같다.
- java.net.URL은 http, https, ftp는 지원하지만 classpath를 기준으로 리소스를 가져오는 기능이 없다.
- ServletContext를 기준으로 상대 경로로 리소스를 가져오는 기능이 없다.
- 새로운 핸들러를 등록하여 URL 접미사를 만들어 사용할수는 있지만 구현이 복잡하고 편의성 메소드가 부족하다.
Spring은 리소스를 추상화하여 리소스를 다루는데 있어 하나의 통일된 인터페이스를 제공한다.
1. Spring에서의 Resource 사용 예
Resource 인터페이스는 spring 내부에서 아주 흔하게 사용된다.
예를 들어 XML 빈 설정파일로 ApplicationContext를 생성하는 코드는 다음과 같다.
1
2
3
|
// ApplicationContext
applicationContext = new ClassPathXmlApplicationContext("config.xml");
applicationContext = new FileSystemXmlApplicationContext("config.xml");
|
cs |
ApplicationContext 구현체의 생성자를 호출할때 설정파일의 경로를 전달하여 생성하는데 지정한 문자열이 getResource("config.xml")와 같이 Resource 객체를 생성해서 내부적으로 Resource를 사용한다.
그런데 여기서 ClassPathXmlApplicationContext()에는 classpath 경로, FileSystemXmlApplicationContext()에는 파일 시스템 경로를 전달하여 ApplicationContext를 생성하는데 각 생성자는 서로 다른 Resource 구현체를 사용한다.
2. Resource의 구현체
Resource의 주요 구현체는 UrlResource, ClassPathResource, FileSystemResource, ServletContextResource가 있다.
- UrlResource: java.net.URL 참고, 프로포콜 http, https, ftp, file, jar 지원
- ClassPathResource: 접두어 classpath: 지원
- FileSystemResource
- ServletContextResource: 웹 어플리케이션 루트에서 상대 경로로 리소스에 접근
이 중 실질적으로 가장 많이 쓰게 되는 것은 ServletContextResource이다.
Resource의 구현체 타입은 리소스 위치를 지정하는 location 파라미터 문자열과 ApplicationContext 구현체 타입에 따라 결정된다.
예를 들어 ApplicationContext가 FileSystemXmlApplicationContext이면 생성자 파라미터 configLocation에 지정되는 문자열은 FileSystemResource로 resolve된다.
또 ApplicationContext가 ClassPathXmlApplicationContext이면 ServletContextResource로 resolve된다.
ApplicationContext는 대부분의 경우 WebApplicationContext 타입을 사용하기 때문에 Resource는 ServletContextResource를 사용하게 된다.
- ClassPathXmlApplicationContext → ClassPathResource
- FileSystemXmlApplicationContext → FileSystemResource
- WebApplicationContext → ServletContextResource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ApplicationContext applicationContext;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationContext: " + applicationContext.getClass());
Resource resource = applicationContext.getResource("test.txt");
System.out.println("Resource: " + resource.getClass());
}
}
|
cs |
실행 결과
위와 같이 WebApplicationContext 타입의 ApplicationContext를 사용하면 getResource()로 얻어지는 Resource의 타입이 기본적으로 ServletContextResource이다.
3. Resource 구현체 타입 강제 지정 방법
ApplicationContext 구현체 타입에 상관없이 Resource 구현체 타입을 강제하려면 java.net.URL 접두어들과 'classpath:' 중 하나를 prefix로 사용하면 된다.
예:
"classpath:com/atoz_develop/config.xml" → ClassPathResource
"file:///some/resource/path/config.xml" → FileSystemResource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ApplicationContext applicationContext;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationContext: " + applicationContext.getClass());
Resource resource = applicationContext.getResource("classpath:test.txt");
System.out.println("Resource: " + resource.getClass());
}
}
|
cs |
실행 결과
위 실행 결과로 getResource()를 호출할때 'classpath:' prefix를 붙여서 전달함으로써 Resource의 타입이 ClassPathResource가 된 것을 확인할 수 있다.
Spring boot 기반의 어플리케이션을 개발할때는 보통 classpath를 기준으로 많은 리소스들을 사용하기때문에 classpath: prefix를 사용하는게 좋다.
WebApplicationContext 타입의 ApplicationContext를 사용하면 기본적으로 ServletContextResource로 resolve된다는 것을 기억하자.
References
'Spring' 카테고리의 다른 글
[Spring] 데이터 바인딩 - PropertyEditor, Converter 그리고 Formatter (1) | 2020.03.06 |
---|---|
[Spring] Validation 추상화 (0) | 2020.03.05 |
[Spring] ResourceLoader로 텍스트 파일 출력하기 (Java 11) (0) | 2020.03.05 |
[Spring] ApplicationEventPublisher를 이용한 이벤트 프로그래밍 (0) | 2020.03.05 |
[Spring] Spring 어플리케이션 메시지 다국어 및 재로딩 처리 (0) | 2020.03.04 |
댓글