Resource를 속성으로 가지는 클래스

Resource로 사용할 파일의 이름이나 위치가 자주 바뀌는 경우에 Resource 타입의 변수를 가지고 있는 클래스의 속성을 configuration 파일에 설정 해두는 것이 편할 수 있습니다.

public class PlainResourceHolder {
    private Resource resource;

    public Resource getResource() {
        return resource;
    }

    public void setResource(Resource resource) {
        this.resource = resource;
    }
}

이렇게 Resource를 가지고 있는 클래스가 있을 때 설정 파일에서도 prefix를 사용해서 Resourc에 값을 넣어 줄 수 있습니다.

<bean id=”holder2″ class=”resource.PlainResourceHolder”>
        <property name=”resource” value=”file:resourceTest.txt” />
</bean>

다음과 같이 테스트를 해보면 원하는 대로 일이 처리 된 걸 확인할 수 있습니다.

    @Test public void resourceFromConfiguration(){
        PlainResourceHolder holder = (PlainResourceHolder)context.getBean(“holder2”);
        Resource resource =  holder.getResource();
        assertTrue(resource.exists());
        assertTrue(resource.getFilename().equals(“resourceTest.txt”));
    }

ResouceLoaderAware 인터페이스

BeanFactoryAware, ApplicationContextAware.. 그리고 ResourceLoaderAware까지.. 대체 뭐가 그렇게 많이 알고 싶은거냐..ㅋㅋ

public interface ResourceLoaderAware {
  void setResourceLoader(ResourceLoader resourceLoader);
}

이 녀석을 구현하면 녀석을 bean으로 등록 해 두면 ApplicationContext가 로딩 될 때 ResourceLoader를 찾아서 DI해줍니다.

ApplicationContext 자체가 근데 이미 ResourceLoader라는 것을 저번 글에서 살펴 봤기 때문에 굳이 ResourceLoader 객체를 따로 만들지 않아도 됩니다.

다음과 같은 테스트를 작성했습니다.

    @Test public void resourceLoaderAware(){
        ResourceHolder holder = (ResourceHolder)context.getBean(“holder”); //1
        Resource resource = holder.getResource(); //2
        assertTrue(resource.exists()); //3
        assertTrue(resource.getFilename().equals(“resourceTest.txt”)); //4
        assertEquals(context.getClass(), holder.getResourceLoader().getClass()); //5
    }

먼저 ResourceLoaderAware 인터페이스를 구현한 ResourceHolder 클래스를 하나 만들었습니다. 기존에 예제에서 사용하던 Member가 구현해도 되겠지만 클래스가 너무 덩치가 커져서요;;

public class ResourceHolder implements ResourceLoaderAware {

    private ResourceLoader resourceLoader;

    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public Resource getResource() {
        return resourceLoader.getResource(“file:resourceTest.txt”);
    }

    public ResourceLoader getResourceLoader(){
        return resourceLoader;
    }
}

resourceLoader 객체가 있다고 치고 그걸 사용해서 getResource를 구현해 줬습니다. 그리고 resourceLoader가 대체 어떤 녀석인지 알아 보기 위해 반환 받아서 테스트 코드의 5번 줄에서 제가 예제에서 계속 사용하고 있는 ClassPathXmlApplicationContext인지 확인해 봤습니다.

테스트는 통과 하였고… ApplicationContext가 자기 자신을 ResourceLoader로써 ResourceLoaderAware 인터페이스를 구현한 클래스의 속성으로 DI 시키는 것을 확인했습니다.

Resource, ResourceLoader 인터페이스 사용 예

간단한 테스트 코드를 작성해 봤습니다.

@Test public void resource(){
        Resource resource = context.getResource(“resourceTest.txt”);
        assertTrue(resource.exists());
    }

ApplicationContext를 ResourceLoader로 사용할 수도 있기 때문에 getResource를 통해서 Resource객체를 받을 수 있습니다.

사용자 삽입 이미지resourceTest.txt 파일의 위치가 위 와 같을 때.. 위의 테스트 코드는 빨간불이 들어옵니다. 대시 file: 이라는 prefix를 붙여 주면 녹색 불이 들어옵니다.

    @Test public void resource(){
        Resource resource = context.getResource(“file:resourceTest.txt”);
        assertTrue(resource.exists());
    }

getResource의 인자로 넘기는 문자열 값에 붙일 수 있는 prefix에는 다음과 같은 것들이 있습니다.

Prefix Example Explanation

classpath:

classpath:com/myapp/config.xml

Loaded from the classpath.

file:

file:/data/config.xml

Loaded as a URL, from the
filesystem. [a]

http:

http://myserver/logo.png

Loaded as a
URL.

(none)

/data/config.xml

Depends on the underlying
ApplicationContext.

아무것도 안붙인 상태에서 에러가 발생한 이유는 현재 사용중인 ApplicationContext가 ClassPathXmlApplicationContext 이녀석이기 때문에 classpath: 를 붙인 것 처럼 동작했기 때문입니다.

ResourceLoader 인터페이스

ResourceLoader 인터페이스의 메소드들 입니다.

ClassLoader     getClassLoader()
          Expose the ClassLoader used by this ResourceLoader.
 Resource     getResource(String location)
          Return a Resource handle for the specified resource.

흠… 이 클래스들을 구현한 클래스들을 보겠습니다.

AbstractApplicationContext, AbstractRefreshableApplicationContext, AbstractRefreshablePortletApplicationContext, AbstractRefreshableWebApplicationContext, AbstractXmlApplicationContext, ClassPathXmlApplicationContext, DefaultResourceLoader, FileSystemResourceLoader, FileSystemXmlApplicationContext, GenericApplicationContext, GenericWebApplicationContext, PathMatchingResourcePatternResolver, PortletContextResourceLoader, PortletContextResourcePatternResolver, ServletContextResourceLoader, ServletContextResourcePatternResolver, StaticApplicationContext, StaticPortletApplicationContext, StaticWebApplicationContext, XmlPortletApplicationContext, XmlWebApplicationContext

엄청 많네요. 대부분이 ApplicationContext입니다. ApplicationContext 인터페이스를 보니 이 인터페이스를 상속 받았군요. 그럼.. “모든 ApplicationContext는 ResourceLoader다.”라는 명제가 성립되네요.

Resource 인터페이스와 클래스들

Resource 인터페이스 extends InputStreamSource
사용자 삽입 이미지InputStreamSource 인터페이스
사용자 삽입 이미지구현한 클래스들

AbstractResource, ByteArrayResource, ClassPathResource, DescriptiveResource, FileSystemResource, InputStreamResource, PortletContextResource, ServletContextResource, UrlResource

계층 구조를 대강 그려보면 다음과 같이 중간에 AbstractResource를 두고 그것을 상속받고 있습니다.

사용자 삽입 이미지