Spring Resource 및 ResourceLoader

1 minute read

ResourceLoader

Spring은 리소스 읽어오는 기능을 제공하는 인터페이스인 ResourceLoader를 제공한다. ApplicationContext에서 제공되는 인터페이스이기 때문에 ResourceLoader 대신 ApplicationContext 객체를 사용해도 된다.

@Component
public class AppRunner implements ApplicationRunner {

	@Autowired
	ResourceLoader resourceLoader;

	@Override
	public void run(ApplicationArguments args) throws Exception {
		Resource resource = resourceLoader.getResource("classpath:test.txt");
		System.out.println(resource.exists());
		
	}	
}

Resource의 추상화

스프링 내부에서 가장 많이 사용하는 인터페이스로 java.net.URL을 추상화 한 것이다. (org.springframework.core.io.Resource)

(java.net.URL이 classpath 기준으로 가져오는 기능이 없었음)


리소스를 읽어오는 방법은 2가지이다.

  • Resource의 타입은 location 문자열과 ApplicationContext 타입에 따라 결정된다.
    • ClassPathXmlApplicationContext → ClassPathResource
    • FileSystemXmlApplicationContext → FileSystemResource
    • WebApplicationContext → ServletContextResource
  • (추천) ApplicationContext 타입에 상관없이 리소스 타입을 강제하려면 java.net.URL 접두어 중 하나를 사용할 수 있다.

    • classpath: → ClassPathResource
    • file: → FileSystemResource


아래 코드로 ApplicationContext 타입이 처음에 어떻게 설정되어 있는지와(ResourceLoader.getClass) 접두어를 사용해서 Resource 구현체를 강제해주었을 때 어떤 타입으로 바꼈는지(resource.getClass) 확인할 수 있다.

	@Autowired
	ResourceLoader resourceLoader;

	@Override
	public void run(ApplicationArguments args) throws Exception {
		System.out.println(resourceLoader.getClass());
		
		Resource resource = resourceLoader.getResource("classpath:test.txt");
		System.out.println(resource.getClass());
		
		System.out.println(resource.exists());
		System.out.println(resource.getDescription()); 
        System.out.println(resource.getURI().getPath());
	}
class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
class org.springframework.core.io.ClassPathResource
true
class path resource [test.txt]
/D:/dev/workspace-spring-tool-suite-4-4.6.0.RELEASE/demo4/target/classes/test.txt

ClassPathResource가 리졸빙 된것을 확인할 수 있다.


위 코드에서 classpath: 접두어를 안쓰고 파일명만 주고 실행을 해보면

...
WebApplicationContext: initialization completed in 1026 ms
2020-05-01 14:44:41.501  INFO 17320 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-05-01 14:44:41.663  INFO 17320 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-01 14:44:41.666  INFO 17320 --- [           main] com.example.demo4.Demo4Application       : Started Demo4Application in 1.792 seconds (JVM running for 2.271)

class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
class org.springframework.web.context.support.ServletContextResource
false
ServletContext resource [/test.txt]
2020-05-01 14:44:41.670  INFO 17320 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-05-01 14:44:41.675 ERROR 17320 --- [           main] o.s.boot.SpringApplication               : Application run failed

java.lang.IllegalStateException: Failed to execute ApplicationRunner

Resource 타입이 ServletContextResource로 리졸빙 되고 Class Path 가 아닌 Context Path부터 파일을 찾게 된다.

스프링 부트의 내장형 톰캣에는 Context Path가 기본적으로 지정이 되있지 않으므로 실제 파일을 참조하려고 하면 에러가 발생한다. (resource.getURI().getPath() 부분)

Spring Boot 기반 프로젝트를 개발할 땐 classpath 기준으로 하기 때문에 되도록이면 접두어를 붙여서 사용하자.

Reference

Resource 인터페이스

ResourceLoader 인터페이스

Categories:

Updated:

Comments