Resource
- java.net.URL을 추상화 한 것
org.springframework.core.io.Resource
라는 클래스로 감싸 실제 low-level의 리소스에 접근하도록 리소스를 추상화한다.- 스프링 내부에서 많이 사용하는 인터페이스이다.
Resource
를 추상화 한 이유
java.net.URL
은 웹상에서 존재하는 자원(프로토콜, 호스트, 포트번호 등등)에 접근할 때 사용된다. 이 클래스는 classPath
기준으로 리소스를 가져오는 방법이 없었다. 하지만 classpath
, url
을 통해 가져오는 두가지 방법 모두 resource를 가져오는 방법이기에, spring에서는 이것을 추상화하여 통일을 시켰다.
ClassPath
란 ?
자바 가상머신이 프로그램을 실행할 때class
파일을 찾는데 기준이 되는 경로를 말한다. 빌드시 컴파일된 class파일의 위치 경로를 말하며,classPath
를 지정하지 않을 경우, 자바 가상머신이 위치한 디렉토리에서만 클래스를 찾을 수 있다.
- 클래스패스 기준으로 리소스를 읽어오는 기능 부재
ServletContext
기준으로 상대 경로를 읽어오는 기능 부재- 새로운 핸들러를 등록하여 특별한 URL 접미사를 만들어 사용할 수 있지만, 구현이 복잡하고 편의성 메소드 부족
Resource
인터페이스의 주요 메소드
getInputStream()
exist()
: 리소스가 존재하는지 확인isOpen()
: 리소스가 열린 상태인지 확인getDescription()
: 전체 경로를 포함한 파일 이름 또는 실제 URL
Resource
구현체
UrlResource
: URL 기준으로 리소스를 읽음. http, https, ftp, file, jar등을 지원ClassPathResource
: classpath를 기준으로 리소스를 읽음FileSystemResource
: 파일 경로 기준으로 리소스를 읽음ServletContextResource
: 웹 어플리케이션 루트에서 상대 경로로 리소스를 찾는다.(가장 많이 쓰인다)
리소스를 읽어오는 방법
Resource
타입은 location 문자열과 ApplicationContext
의 타입에 따라 결정된다.
- ClassPathXmlApplicationContext -> ClassPathResource
- FileSystemXmlApplicationContext -> FileSystemResource
- WebApplicationContext -> ServletContextResource
@Override
public void run(ApplicationArguments args) throws Exception {
var ctx = new ClassPathXmlApplicationContext("blabla.xml"); //xml이 리소스로 변환된다. 아래와 같이 변환된다고 볼 수 있다.
Resource resource = resourceLoader.getResource("~~~"); // getResource 안의 파라미터 변수 안으로 들어간다.
}
위와 같이 작성한 blabla.xml
이라는 로케이션 문자열은 Resource
로 변환이 된다. 이 때, ApplicationContext
타입이 ClassPathXmlApplicationContext
이기 때문에 ClassPathResource
로 생성이 된다.
@Override
public void run(ApplicationArguments args) throws Exception {
var ctx = new FileSystemXmlApplicationContext("blabla.xml"); //xml이 리소스로 변환된다. 파일시스템 경로 기준으로 문자열에 해당되는 로케이션을 찾아서 변환한다.
Resource resource = resourceLoader.getResource("~~~"); // getResource 안의 파라미터 변수 안으로 들어간다.
}
위와 같이 작성하게 되면FileSystemXmlApplicationContext
기준으로 생성하기 때문에 FileSystemResource
로 리소스가 생성된다.
추가로, ApplicationContext
인터페이스는 ResourcePatternResolver
를 구현함으로써 ResourceLoader
를 상속받는다. 따라서 ResourceLoader
의 기능을 가지고 있다고 볼 수 있다. ApplicationContext
가 ClassPathXmlApplicationContext
라면 classpath를 적어주지 않아도 ClassPathResource
로 읽어온다.
ApplicationContext의 타입에 상관없이 리소스 타입을 강제하려면 java.net.URL
접두어(+classpath:) 중 하나를 사용할 수 있다.
- classpath:me/cjk/config.xml -> ClassPathResource
- file:///some/resource/path/config.xml -> FileSystemResource
이 방법은 접두어를 사용하기 때문에 명시적으로 키워드를 적어주면, 코드만 보고 클래스경로로 오는지 파일경로로 오는지 직관적으로 알 수 있기에 이 방법을 더 추천한다.
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 resourceLoader;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(resourceLoader.getClass());
Resource resource = resourceLoader.getResource("classpath:text.txt");
System.out.println(resource.getClass());
System.out.println(resource.exists());
}
}
class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
class org.springframework.core.io.ClassPathResource
true
위와 같이 getResource
에서 접두어로 classpath
를 명시해줌으로써 리소스의 클래스는 ClassPathResource
로 출력되는 것을 확인할 수 있다. 여기서 접두어를 제거하고 실행하게 되면 아래와 같이 ServletContextResource
로 출력된다.
class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
class org.springframework.web.context.support.ServletContextResource
false
이는 스프링 부트가 생성하는 applicationContext가 기본으로 서블릿 기반 WebApplicationContext
이기 때문에 ServletContextResource
로 생성되었다고 볼 수 있다.
참고 자료