Spring/about spring

[Resource / Validation] Resource 추상화

dev_rosieposie 2023. 7. 25. 12:38

Goal 

  1. 스프링의 추상화 중 하나인 Resource 추상화에 대해 알아본다
  2. 추상화를 한 이유에 대해 알아본다
  3. Resource 인터페이스의 동작과정과 구현체를 알아본다
  4. Resource를 읽어오는 방법에 대해 알아본다

Resource 추상화란 ? 

  • 구체적으로 java.net.URL를 추상화 한 것
  • org.springframework.core.io.Resource 클래스로 감싸서 로우 레벨에 접근하는 기능을 추상화하였다.

가져오는 기능은 아래 포스팅 참고

https://dev-rosiepoise.tistory.com/99

 

[IoC 컨테이너와 빈] ResourceLoader

Goal ApplicationContext의 Resource Loader에 대해 알아본다 ResourceLoader란? 리소스를 읽어오는 기능을 제공하는 인터페이스 public interface ApplicationContext extends ResourcePatternResolver public interface ResourcePatternResolv

dev-rosiepoise.tistory.com

스프링이 Resource를 왜 추상화 하였는가? 

  • classpath 기준으로 리소스 읽어오는 기능의 부재
    • 기존의 java.net.URL은 기본적으로 지원하는 프로토콜이 http, https, ftp, file, jar
  • ServletContext를 기준으로 상대 경로를 읽어오는 기능 부재
  • 새로운 핸들러를 등록하여 특별한 URL 접미사를 만들어 사용할 수 있지만 복잡하고 편의성 메소드 부족

Resource 인터페이스 

public interface Resource extends InputStreamSource
  • InputStreamSource를 구현
    • getInputStream()
  • 주요 메소드 // java 8이상 인터페이스의 default메소드
    • default boolean isReadable() {return this.exists();}  // 항상 존재한다고 가정하지 않기 때문에 확인
    • default boolean isOpen() {return false;}
    • default boolean isFile() {return false;}
  • String getDescription(); 
    • 전체 경로 포함한 파일 이름 또는 실제 URL
  • File getFile() throws IOException;
    • 항상 모든 리소스를  파일로 가져올 수 있는 것은 아님

동작과정

var ctx = new ClassPathXmlApplicationContext("test.xml");

classpath 기준으로 내부적으로 location("test.xml"라는 문자열)에 해당하는 리소스를 찾아서 빈 설정파일로 사용

var ctx = new FileSystemXmlApplicationContext("test.xml");

file system 경로 기준으로 내부적으로 location("test.xml"라는 문자열)에 해당하는 리소스를 찾아서 빈 설정파일로 사용

구현체

  • UrlResource
  • ClassPathResource
    • classpath 접두어 사용
  • FileSystemResource
  • ServletContextResource
    • 웹 어플리케이션 루트에서 상대 경로로 리소스 찾는다
    • 읽어들이는 리소스 타입이 applicationContext와 관련이 있기 때문에 가장 많이 쓰인다

Resource 읽어오기 

Resource의 타입은 location 문자열과 ApplicationContext 타입에 따라 결정 된다

  • ClassPathXmlApplicationContext -> ClassPathResource
  • FileSystemXmlApplicationContext -> FileSystemResource
  • WebApplicationContext -> ServletContextResource
    • WebApplicationContext 이하로는 ServletContextResource를 사용한다

ApplicationContext의 타입에 상관없이 리소르 타입을 강제하려면 java.net.URL 접두어(+classpath:)중 하나를 사용 가능

접두어를 사용하면 보다 명시적이기 때문에, 이 방법을 추천한다.

  • classpath:com/demo/config.xml -> ClassPathResource
  • file:///some/resource/path/config.xml -> FileSystemResource

검증하기 

classpath 접두어를 사용한 경우

@Component
public class AppRunner implements ApplicationRunner {
    @Autowired
    ResourceLoader 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());
        System.out.println(resource.getDescription());
        System.out.println(Files.readString(Path.of(resource.getURI())));
    }
}

결과

class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
class org.springframework.core.io.ClassPathResource

true
class path resource [text.txt]
hello spring

 

classpath 접두어를 사용하지 않은 경우

@Component
public class AppRunner implements ApplicationRunner {
    @Autowired
    ResourceLoader resourceLoader;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        System.out.println(resourceLoader.getClass());
        Resource resource =  resourceLoader.getResource("text.txt");
        System.out.println(resource.getClass());
        
        System.out.println(resource.exists());
        System.out.println(resource.getDescription());
        System.out.println(Files.readString(Path.of(resource.getURI())));
    }
}

결과

class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
class org.springframework.web.context.support.ServletContextResource
false
ServletContext resource [/text.txt]

2023-07-25T12:34:11.325+09:00  INFO 43812 --- [           main] .s.b.a.l.ConditionEvaluationReportLogger : 

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2023-07-25T12:34:11.345+09:00 ERROR 43812 --- [           main] o.s.boot.SpringApplication               : Application run failed

java.lang.IllegalStateException: Failed to execute ApplicationRunner

 

=> 해당하는 리소스를 찾지 못했고, 없는 파일을 읽으려고 시도하였기 때문에 에러 발생 

 

 

 

참고

스프링입문 강의 by 백기선

https://www.inflearn.com/course/lecture?courseSlug=spring&unitId=15538 https://www.inflearn.com/course/spring_revised_edition/dashboard

https://www.inflearn.com/course/spring_revised_edition/dashboard