while(1) work();
반응형

Resources

이 장에서는 Spring이 리소스를 처리하는 방법과 Spring에서 리소스로 작업하는 방법을 다룹니다. 여기에는 다음 주제가 포함됩니다:

Introduction

안타깝게도 Java의 표준 java.net.URL 클래스와 다양한 URL 접두사에 대한 표준 핸들러는 저수준 리소스에 대한 모든 액세스에 충분히 적합하지 않습니다. 예를 들어, 클래스 경로에서 가져와야 하는 리소스에 액세스하는 데 사용할 수 있는 표준화된 URL 구현이 없거나서블릿 컨텍스트에 상대적일 수 있습니다. 특수 URL접두사에 대한 새 핸들러를 등록할 수는 있지만( http: 등의 접두사에 대한 기존 핸들러와 유사), 이는 일반적으로 상당히 복잡하며 URL 인터페이스에는 가리키는 리소스의 존재 여부를 확인하는 방법과 같은 일부 바람직한 기능이 여전히 부족합니다.

The Resource Interface

패키지에 있는 Spring의 Resource 인터페이스는 낮은 수준의 리소스에 대한 액세스를 추상화하기 위한 보다 강력한 인터페이스를 의미합니다. 다음 목록은 Resource 인터페이스에 대한 개요를 제공합니다. 자세한 내용은Resource 자바독을 참조하세요.

public interface Resource extends InputStreamSource {

	boolean exists();

	boolean isReadable();

	boolean isOpen();

	boolean isFile();

	URL getURL() throws IOException;

	URI getURI() throws IOException;

	File getFile() throws IOException;

	ReadableByteChannel readableChannel() throws IOException;

	long contentLength() throws IOException;

	long lastModified() throws IOException;

	Resource createRelative(String relativePath) throws IOException;

	String getFilename();

	String getDescription();
}

Resource 인터페이스의 정의에서 알 수 있듯이 이 인터페이스는 InputStreamSource인터페이스를 확장합니다. 다음 목록은 InputStreamSource인터페이스의 정의를 보여줍니다:

public interface InputStreamSource {

	InputStream getInputStream() throws IOException;
}

Resource 인터페이스의 가장 중요한 메서드는 다음과 같습니다:

  • getInputStream(): 리소스를 찾아서 열고, 리소스에서 읽을 수 있도록 InputStream을 반환합니다. 각 호출은 새로운InputStream을 반환할 것으로 예상됩니다. 스트림을 닫는 것은 호출자의 책임입니다.
  • exists(): 이 리소스가 실제로 물리적 형태로 존재하는지 여부를 나타내는 부울을 반환합니다.
  • isOpen(): 이 리소스가 스트림이 열려 있는 핸들을 나타내는지 여부를 나타내는 부울을 반환합니다. True이면 InputStream은 여러 번 읽을 수 없으며 리소스 누수를 방지하기 위해 한 번만 읽은 다음 닫아야 합니다. InputStreamResource를 제외한 모든 일반적인 리소스 구현에서는 false를 반환합니다.
  • getDescription(): 리소스로 작업할 때 오류 출력에 사용할 이 리소스에 대한 설명을 반환합니다. 리소스의 정규화된 파일 이름 또는 실제 URL인 경우가 많습니다.

다른 메서드를 사용하면 리소스를 나타내는 실제 URL 또는 파일 객체를 얻을 수 있습니다(기본 구현이 호환되고 해당 기능을 지원하는 경우).

Resource 인터페이스의 일부 구현은 쓰기를 지원하는 리소스에 대해 확장된WritableResource 인터페이스를 구현하기도 합니다.

Spring 자체는 리소스가 필요할 때 많은 메서드 시그니처에서 인수 유형으로 Resource 추상화를 광범위하게 사용합니다. 일부 Spring API의 다른 메서드(예: 다양한 ApplicationContext 구현의 생성자)는 꾸밈이 없거나 단순한 형태로 해당 컨텍스트 구현에 적합한 Resource를 생성하는 데 사용되는String을 받거나 String 경로의 특수 접두사를 통해 호출자가 특정 Resource 구현을 생성하고 사용하도록 지정할 수 있습니다.

Resource 인터페이스는 Spring과 Spring에 의해 많이 사용되지만, 실제로는 코드에서 Spring의 다른 부분을 모르거나 신경 쓰지 않는 경우에도 리소스에 액세스하기 위해 코드 자체에서 일반 유틸리티 클래스로 사용하는 것이 매우 편리합니다. 이것은 코드를 Spring에 결합하지만 실제로는 이 작은 유틸리티 클래스 집합에만 결합되며, 이는 URL을 더 잘 대체하는 역할을 하며 이러한 목적으로 사용하는 다른 라이브러리와 동등한 것으로 간주할 수 있습니다.

  리소스 추상화는 기능을 대체하지 않습니다. 가능한 경우 기능을 래핑합니다. 예를 들어 UrlResource는 URL을 래핑하고 래핑된 URL을 사용하여 작업을 수행합니다

Built-in Resource Implementations

Spring에는 몇 가지 내장된 리소스 구현이 있습니다:

Spring에서 사용 가능한 리소스 구현의 전체 목록은리소스 자바독의 "모든 알려진 구현 클래스" 섹션을 참조하세요.

UrlResource

UrlResource는 java.net.URL을 래핑하며 파일, HTTPS 대상, FTP 대상 등과 같이 일반적으로 URL로 액세스할 수 있는 모든 객체에 액세스하는 데 사용할 수 있습니다. 모든 URL은 표준화된 문자열 표현을 사용하므로 적절한 표준화된 접두사를 사용하여 한 URL 유형과 다른 유형을 구분할 수 있습니다. 여기에는file: 파일 시스템 경로에 액세스하는 경우, https: HTTPS 프로토콜을 통해 리소스에 액세스하는 경우, ftp: FTP를 통해 리소스에 액세스하는 경우 등이 포함됩니다.

UrlResource는 Java 코드에서 UrlResource 생성자를 명시적으로 사용하여 생성되지만, 경로를 나타내는 문자열인수를 받는 API 메서드를 호출할 때 암시적으로 생성되는 경우도 많습니다. 후자의 경우, 생성할 리소스 유형은 최종적으로 JavaBeans PropertyEditor가결정합니다. 경로 문자열에 (속성 편집기에) 잘 알려진 접두사(예 : classpath:)가 포함되어 있으면 해당 접두사에 적합한 특수 리소스를 생성합니다. 그러나 접두사를 인식하지 못하면 문자열이 표준 URL 문자열이라고 가정하고 UrlResource를 생성합니다.

ClassPathResource

이 클래스는 클래스 경로에서 가져와야 하는 리소스를 나타냅니다. 이 클래스는 스레드 컨텍스트 클래스 로더, 지정된 클래스 로더 또는 지정된 클래스를 사용하여 리소스를 로드합니다.

 리소스 구현은 클래스 경로 리소스가 파일 시스템에 있는 경우 java.io.File로 확인을 지원하지만, jar에 있고 (서블릿 엔진이나 환경에 따라) 파일 시스템으로 확장되지 않은 클래스 경로 리소스의 경우에는 지원하지 않습니다. 이 문제를 해결하기 위해 다양한 리소스 구현은 항상 java.net.URL로 확인을 지원합니다.

클래스 경로 리소스는 명시적으로 클래스경로 리소스 생성자를 사용하여 Java 코드에 의해 생성되지만, 경로를 나타내는문자열 인수를 사용하는 API 메서드를 호출할 때 암시적으로 생성되는 경우가 많습니다. 후자의 경우 JavaBeans속성 편집기는 문자열 경로에서 특수 접두사 classpath: 를 인식하고 해당 경우 ClassPathResource를 생성합니다.

파일 시스템 리소스

Java.io.File 핸들을 위한 리소스 구현입니다. 또한 Spring의 표준 문자열 기반 경로 변환을 적용하지만 모든 작업을 java. nio.file. Files API를 통해 수행하는 java.nio.file.Path 핸들을 지원합니다. 순수한java.nio.path.Path 기반 지원의 경우 대신 PathResource를 사용합니다. FileSystemResource는 파일  URL로 확인을 지원합니다.

PathResource

Path API를 통해 모든 작업과 변환을 수행하는 java.nio.file.Path 핸들에 대한 리소스 구현입니다. 파일  URL로 확인을 지원하며 확장된 WritableResource 인터페이스도 구현합니다. PathResource는사실상 FileSystemResource에 대한 순수한 java.nio.path.Path 기반 대안으로, createRelative 동작이 다릅니다.

서블릿 컨텍스트 리소스

관련 웹 애플리케이션의 루트 디렉토리 내에서 상대 경로를 해석하는 ServletContext 리소스에 대한 리소스 구현입니다.

항상 스트림 액세스와 URL 액세스를 지원하지만 웹 애플리케이션 아카이브가 확장되고 리소스가 물리적으로 파일 시스템에 있는 경우에만 java.io.File 액세스를 허용합니다. 확장되어 파일시스템에 있는지 또는 JAR 또는 데이터베이스와 같은 다른 곳에서 직접 액세스하는지 여부는 실제로 Servlet 컨테이너에 따라 달라집니다(상상할 수 있음).

입력 스트림 리소스

InputStreamResource는 주어진 입력 스트림에 대한 리소스 구현입니다. 특정 리소스 구현이 적용되지 않는 경우에만 사용해야 합니다. 특히 가능하면 ByteArrayResource 또는 파일 기반 리소스구현을 선호합니다.

다른 리소스 구현과 달리 이미 열려 있는 리소스에 대한 설명자입니다. 따라서 isOpen()에서 참을 반환합니다. 리소스 디스크립터를 어딘가에 보관해야 하거나 스트림을 여러 번 읽어야 하는 경우에는 사용하지 마세요.

바이트 배열 리소스

주어진 바이트 배열에 대한 리소스 구현입니다. 주어진 바이트 배열에 대한ByteArrayInputStream을 생성합니다.

일회용 InputStreamResource를 사용하지 않고도 주어진 바이트 배열에서 콘텐츠를 로드할 때 유용합니다.

The ResourceLoader Interface

ResourceLoader 인터페이스는 리소스 인스턴스를 반환(즉, 로드)할 수 있는 객체에 의해 구현되어야 합니다. 다음 목록은 ResourceLoader인터페이스 정의를 보여줍니다:

public interface ResourceLoader {

	Resource getResource(String location);

	ClassLoader getClassLoader();
}

모든 애플리케이션 컨텍스트는 ResourceLoader 인터페이스를 구현합니다. 따라서 모든 애플리케이션 컨텍스트를 사용하여 리소스 인스턴스를 가져올 수 있습니다.

특정 애플리케이션 컨텍스트에서 getResource() 를 호출할 때 지정된 위치 경로에 특정 접두사가 없으면 해당 특정 애플리케이션 컨텍스트에 적합한 리소스 유형이 반환됩니다. 예를 들어 다음 코드 조각이 ClassPathXmlApplicationContext 인스턴스에 대해 실행되었다고 가정해 보겠습니다:

Resource template = ctx.getResource("some/resource/path/myTemplate.txt");

이 코드는 ClassPathXmlApplicationContext에 대해 ClassPathResource를 반환합니다. 동일한 메서드가 FileSystemXmlApplicationContext 인스턴스에 대해 실행되면 FileSystemResource를 반환합니다. 웹 애플리케이션 컨텍스트의 경우서블릿 컨텍스트 리소스를 반환합니다. 마찬가지로 각 컨텍스트에 적합한 객체를 반환합니다.

따라서 특정 애플리케이션 컨텍스트에 적합한 방식으로 리소스를 로드할 수 있습니다.

반면에 다음 예제에서 볼 수 있듯이 특수 classpath: 접두사를 지정하여 애플리케이션 컨텍스트 유형에 관계없이 ClassPathResource를 강제로 사용할 수도 있습니다:

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");

마찬가지로 표준java.net.URL 접두사 중 하나를 지정하여 UrlResource를 강제로 사용할 수 있습니다. 다음 예에서는 파일  https 접두사를 사용합니다:

Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");

다음 표에는 문자열 개체를 리소스개체로 변환하는 전략이 요약되어 있습니다:

표 1. 리소스 문자열접두사예제설명
classpath: classpath:com/myapp/config.xml 클래스 경로에서 로드합니다.
파일에서 로드합니다: file:///data/config.xml 파일 시스템에서 URL로 로드됩니다. 파일시스템 리소스 주의 사항도 참조하세요.
https: https://myserver/logo.png URL로 로드됩니다.
(없음) /data/config.xml 기본 애플리케이션 컨텍스트에 따라 다릅니다.

The ResourcePatternResolver Interface

ResourcePatternResolver 인터페이스는 위치 패턴(예: Ant 스타일 경로 패턴)을 리소스 객체로 해석하는 전략을 정의하는 ResourceLoader 인터페이스의 확장입니다.

public interface ResourcePatternResolver extends ResourceLoader {

	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

	Resource[] getResources(String locationPattern) throws IOException;
}

위에서 볼 수 있듯이 이 인터페이스는 클래스 경로에서 일치하는 모든 리소스에 대한 특수 classpath*: 리소스 접두사도 정의합니다. 이 경우 리소스 위치는 자리 표시자가 없는 경로(예:classpath*:/config/beans.xml)가 될 것으로 예상됩니다. 클래스 경로의 JAR 파일 또는 다른 디렉터리에는 동일한 경로와 동일한 이름을 가진 파일이 여러 개 포함될 수 있습니다. Classpath*: resource 접두사를 사용한 와일드카드 지원에 대한 자세한 내용은애플리케이션 컨텍스트 생성자 리소스 경로의 와일드카드 및 해당 하위 섹션을 참조하세요.

전달된 ResourceLoader (예:ResourceLoaderAware 시맨틱을 통해 제공된 것)도 이 확장 인터페이스를 구현하는지 확인할 수 있습니다.

PathMatchingResourcePatternResolver는 ApplicationContext 외부에서 사용할 수 있는 독립형 구현이며 Resource [] 빈 프로퍼티를 채우기 위해 ResourceArrayPropertyEditor에서 사용되기도 합니다. PathMatchingResourcePatternResolver는 지정된 리소스 위치 경로를 하나 이상의 일치하는 리소스 객체로 확인할 수 있습니다. 소스 경로는 대상리소스에 일대일 매핑이 있는 단순한 경로일 수도 있고, 특수 classpath*: 접두사나 내부 Ant 스타일 정규식(Spring의org.springframework.util.AntPathMatcher 유틸리티를 사용하여 일치)을 포함할 수도 있습니다. 후자는 모두 사실상 와일드카드입니다.

 
모든 표준 ApplicationContext의 기본 ResourceLoader는 실제로 ResourcePatternResolver인터페이스를 구현하는 PathMatchingResourcePatternResolver의 인스턴스입니다. ResourcePatternResolver 인터페이스를 구현하고 기본PathMatchingResourcePatternResolver에 위임하는 ApplicationContext 인스턴스 자체도 마찬가지입니다.

The ResourceLoaderAware Interface

ResourceLoaderAware 인터페이스는 리소스로더 참조가 제공될 것으로 예상되는 컴포넌트를 식별하는 특수 콜백 인터페이스입니다. 다음 목록은 ResourceLoaderAware 인터페이스의 정의를 보여줍니다:

public interface ResourceLoaderAware {

	void setResourceLoader(ResourceLoader resourceLoader);
}

클래스가 ResourceLoaderAware를 구현하고 애플리케이션 컨텍스트에 배포되면(Spring 관리 빈으로), 애플리케이션 컨텍스트에서 ResourceLoaderAware로 인식됩니다. 그런 다음 애플리케이션 컨텍스트는 자신을 인수로 제공하는 setResourceLoader(ResourceLoader)를 호출합니다(Spring의 모든 애플리케이션 컨텍스트는 ResourceLoader 인터페이스를 구현한다는 점을 기억하세요).

애플리케이션 컨텍스트는 리소스로더이므로 빈은애플리케이션 컨텍스트 인식 인터페이스를 구현하고 제공된 애플리케이션 컨텍스트를 직접 사용하여 리소스를 로드할 수도 있습니다. 그러나 일반적으로 필요한 모든 것이 있다면 특화된 ResourceLoader인터페이스를 사용하는 것이 좋습니다. 이 코드는 유틸리티 인터페이스로 간주될 수 있는 리소스 로딩 인터페이스에만 결합되고 전체 SpringApplicationContext 인터페이스에는 결합되지 않습니다.

애플리케이션 컴포넌트에서는 리소스 로더 인식 인터페이스를 구현하는 대신 리소스 로더의 자동 배선에 의존할 수도 있습니다. 기존의생성자  byType 자동 배선 모드( 자동 배선 협력자에서 설명)는 각각 생성자 인수 또는 설정자 메서드 매개 변수에 대해 ResourceLoader를 제공할 수 있습니다. 필드 및 여러 매개변수 메서드를 자동 배선하는 기능을 포함하여 더 많은 유연성을 원한다면 어노테이션 기반 자동 배선 기능을 사용하는 것을 고려하세요. 이 경우 해당 필드, 생성자 또는 메서드에 @Autowired 어노테이션이 있는 한 ResourceLoader 유형이 예상되는 필드, 생성자 인수 또는 메서드 파라미터에 ResourceLoader가 자동 연결됩니다. 자세한 내용은 @Autowired 사용을 참조하세요.

  와일드카드를 포함하거나 특수 classpath*: resource 접두사를 사용하는 리소스 경로에 대해 하나 이상의 Resource 객체를 로드하려면 ResourceLoader 대신 애플리케이션 컴포넌트에ResourcePatternResolver 인스턴스를 자동 연결해 두는 것을 고려하세요

Resources as Dependencies

빈 자체가 일종의 동적 프로세스를 통해 리소스 경로를 결정하고 제공하려는 경우, 리소스를 로드하기 위해 ResourceLoader 또는ResourcePatternResolver 인터페이스를 사용하는 것이 합리적일 수 있습니다. 예를 들어, 필요한 특정 리소스가 사용자의 역할에 따라 달라지는 일종의 템플릿을 로드하는 경우를 생각해 보겠습니다. 리소스가 정적 리소스인 경우ResourceLoader 인터페이스(또는 ResourcePatternResolver 인터페이스)의 사용을 완전히 없애고 빈이 필요한 리소스 속성을 노출하도록 한 다음 해당 속성이 주입될 것으로 예상하는 것이 합리적입니다.

이러한 프로퍼티를 주입하는 것이 간단한 이유는 모든 애플리케이션 컨텍스트가 문자열 경로를 리소스 객체로 변환할 수 있는 특수 JavaBeans PropertyEditor를 등록하고 사용하기 때문입니다. 예를 들어, 다음 MyBean 클래스에는 Resource 유형의 템플릿프로퍼티가 있습니다.

public class MyBean {

	private Resource template;

	public setTemplate(Resource template) {
		this.template = template;
	}

	// ...
}

XML 구성 파일에서 다음 예제와 같이 해당 리소스에 대한 간단한 문자열로 템플릿 속성을 구성할 수 있습니다:

<bean id="myBean" class="example.MyBean">
	<property name="template" value="some/resource/path/myTemplate.txt"/>
</bean>

리소스 경로에는 접두사가 없습니다. 따라서 애플리케이션 컨텍스트 자체가 ResourceLoader로 사용되므로 리소스는 애플리케이션 컨텍스트의 정확한 유형에 따라ClassPathResource, FileSystemResource 또는 ServletContextResource를 통해 로드됩니다.

특정 리소스 유형을 강제로 사용해야 하는 경우 접두사를 사용할 수 있습니다. 다음 두 예제는 ClassPathResource와 UrlResource (후자는 파일 시스템의 파일에 액세스하는 데 사용됨)를 강제로 사용하는 방법을 보여줍니다:

<property name="template" value="classpath:some/resource/path/myTemplate.txt">
<property name="template" value="file:///some/resource/path/myTemplate.txt"/>

MyBean 클래스가 어노테이션 기반 구성과 함께 사용하도록 리팩터링된 경우, myTemplate.txt의 경로는 template.path라는키 아래에 저장될 수 있습니다(예: Spring환경에서 사용할 수 있는 속성 파일 참조). 그런 다음 속성 자리 표시자를 사용하여 @Value어노테이션을 통해 템플릿 경로를 참조할 수 있습니다( @Value 사용 참조). Spring은 템플릿 경로의 값을 문자열로 검색하고 특수 PropertyEditor가 문자열을 Resource 객체로 변환하여 MyBean 생성자에 주입합니다. 다음 예제는 이를 수행하는 방법을 보여줍니다.

@Component
public class MyBean {

	private final Resource template;

	public MyBean(@Value("${template.path}") Resource template) {
		this.template = template;
	}

	// ...
}

클래스 경로의 여러 위치에서 동일한 경로로 발견된 여러 템플릿을 지원하려면(예: 클래스 경로의 여러 jar에서) 특수 classpath*: 접두사와 와일드카드를 사용하여 templates.path 키를classpath*:/config/templates/*.txt로 정의할 수 있습니다. 다음과 같이 MyBean 클래스를 재정의하면 Spring은 템플릿 경로 패턴을 MyBean 생성자에 주입할 수 있는 Resource 객체 배열로 변환합니다.

@Component
public class MyBean {

	private final Resource[] templates;

	public MyBean(@Value("${templates.path}") Resource[] templates) {
		this.templates = templates;
	}

	// ...
}

Application Contexts and Resource Paths

이 섹션에서는 XML과 함께 작동하는 바로 가기, 와일드카드 사용 방법 및 기타 세부 사항을 포함하여 리소스를 사용하여 애플리케이션 컨텍스트를 만드는 방법에 대해 설명합니다.

애플리케이션 컨텍스트 생성하기

애플리케이션 컨텍스트 생성자(특정 애플리케이션 컨텍스트 유형의 경우)는 일반적으로 컨텍스트의 정의를 구성하는 XML 파일과 같은 리소스의 위치 경로로 문자열 또는 문자열 배열을 사용합니다.

이러한 위치 경로에 접두사가 없는 경우, 해당 경로에서 작성되고 빈 정의를 로드하는 데 사용되는 특정 리소스 유형은 특정 애플리케이션 컨텍스트에 따라 달라지며 해당 컨텍스트에 적합합니다. 예를 들어, 다음 예제에서는ClassPathXmlApplicationContext를 생성합니다:

ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");

ClassPathResource가 사용되므로 클래스 경로에서 빈 정의가 로드됩니다. 그러나 FileSystemXmlApplicationContext를 생성하는 다음 예제를 고려해 보십시오:

ApplicationContext ctx =
	new FileSystemXmlApplicationContext("conf/appContext.xml");

이제 빈 정의는 파일 시스템 위치(이 경우 현재 작업 디렉터리를 기준으로)에서 로드됩니다.

위치 경로에 특수 classpath 접두사 또는 표준 URL 접두사를 사용하면 빈 정의를 로드하기 위해 생성된 기본 리소스 유형이 재정의됩니다. 다음 예제를 살펴보겠습니다:

ApplicationContext ctx =
	new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");

FileSystemXmlApplicationContext를 사용하면 클래스 경로에서 빈 정의가 로드됩니다. 그러나 여전히 FileSystemXmlApplicationContext입니다. 이후에리소스 로더로 사용되는 경우 접두사가 없는 경로는 여전히 파일 시스템 경로로 취급됩니다.

ClassPathXmlApplicationContext 인스턴스 생성 - 단축키

ClassPathXmlApplicationContext는 편리한 인스턴스화를 위해 여러 생성자를 노출합니다. 기본 아이디어는 선행 경로 정보 없이 XML 파일 자체의 파일 이름만 포함된 문자열 배열만 제공하고 클래스도 제공할 수 있다는 것입니다. 그러면 ClassPathXmlApplicationContext는 제공된 클래스에서 경로 정보를 도출합니다.

다음 디렉토리 레이아웃을 고려하세요:

com/ example/ services.xml repositories.xml MessengerService.class

다음 예는 (클래스 경로에 있는) services.xml  repositories.xml이라는 파일에 정의된 빈으로 구성된 ClassPathXmlApplicationContext 인스턴스를 인스턴스화하는 방법을 보여줍니다:

ApplicationContext ctx = new ClassPathXmlApplicationContext(
	new String[] {"services.xml", "repositories.xml"}, MessengerService.class);

다양한 생성자에 대한 자세한 내용은 ClassPathXmlApplicationContext자바독을 참조하세요.

애플리케이션 컨텍스트 생성자 리소스 경로의 와일드카드

애플리케이션 컨텍스트 생성자 값의 리소스 경로는 대상 리소스에 대한 일대일 매핑이 있는 단순한 경로(앞서 표시된 것처럼)일 수도 있고, 특수 classpath*: 접두사 또는 내부 Ant 스타일 패턴(Spring의 PathMatcher 유틸리티를 사용하여 일치)을 포함할 수도 있습니다. 후자는 모두 사실상 와일드카드입니다.

이 메커니즘의 한 가지 용도는 컴포넌트 스타일의 애플리케이션 어셈블리를 수행해야 할 때입니다. 모든 컴포넌트는 컨텍스트 정의 조각을 잘 알려진 위치 경로에 게시할 수 있으며,클래스 경로*: 접두사가 붙은 동일한 경로를 사용하여 최종 애플리케이션 컨텍스트가 생성되면 모든 컴포넌트 조각이 자동으로 선택됩니다.

이 와일드카드는 애플리케이션 컨텍스트 생성자에서 리소스 경로를 사용하는 경우(또는 PathMatcher 유틸리티 클래스 계층 구조를 직접 사용하는 경우)에만 해당되며, 구성 시점에 해결됩니다. 리소스 유형 자체와는 관련이 없습니다. 리소스는 한 번에 하나의 리소스만 가리키므로 실제 리소스를 구성하는 데 classpath*: 접두사를 사용할 수 없습니다.

Ant 스타일 패턴

경로 위치는 다음 예제에서 볼 수 있듯이 Ant 스타일 패턴을 포함할 수 있습니다:

/WEB-INF/*-context.xml com/mycompany/**/applicationContext.xml file:C:/some/path/*-context.xml classpath:com/mycompany/**/applicationContext.xml

경로 위치에 Ant 스타일 패턴이 포함되어 있으면 리졸버는 더 복잡한 절차를 따라 와일드카드를 확인하려고 시도합니다. 와일드카드가 아닌 마지막 세그먼트까지의 경로에 대한 리소스를 생성하고 이로부터 URL을 가져옵니다. 이 URL이 jar가 아닌 경우 URL 또는 컨테이너별 변형(예 : WebLogic의 zip:, WebSphere의 wsjar 등)이 아닌 경우 java.io.File을 가져와 파일 시스템을 트래버스하여 와일드카드를 확인하는 데 사용합니다. Jar URL의 경우, 리졸버는java.net.JarURLConnection을 가져오거나 jar URL을 수동으로 구문 분석한 다음 jar 파일의 내용을 트래버스하여 와일드카드를 확인합니다.

이식성에 미치는 영향

지정된 경로가 이미 파일 URL인 경우(기본리소스로더가 파일 시스템 경로이기 때문에 암시적으로 또는 명시적으로) 와일드카드는 완전히 이식 가능한 방식으로 작동하도록 보장됩니다.

지정된 경로가 클래스 경로 위치인 경우, 리졸버는 Classloader.getResource() 호출을 통해 와일드카드가 아닌 마지막 경로 세그먼트 URL을 가져와야 합니다. 이것은 단지 경로의 노드(끝에 있는 파일이 아님)이기 때문에, 이 경우 정확히 어떤 종류의 URL이 반환되는지는 실제로 (ClassLoader 자바독에서) 정의되지 않습니다. 실제로는 항상 디렉터리(클래스 경로 리소스가 파일 시스템 위치로 확인되는 경우)를 나타내는 java.io.File이거나 일종의 jar URL(클래스 경로 리소스가 jar 위치로 확인되는 경우)입니다. 하지만 이 작업에는 이식성 문제가 있습니다.

와일드카드가 아닌 마지막 세그먼트에 대한 jar URL을 얻은 경우, 리졸버는 java.net.JarURLConnection을 가져오거나 jar URL을 수동으로 구문 분석하여 jar의 내용을 탐색하고 와일드카드를 확인할 수 있어야 합니다. 이 방법은 대부분의 환경에서 작동하지만 다른 환경에서는 실패할 수 있으며, jar에서 오는 리소스의 와일드카드 확인은 특정 환경에서 철저히 테스트한 후 사용하는 것이 좋습니다.

클래스 경로*: 접두사

XML 기반 애플리케이션 컨텍스트를 구성할 때 다음 예에서 보는 것처럼 위치 문자열에 특수 classpath*: 접두사를 사용할 수 있습니다:

ApplicationContext ctx =
	new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");

이 특수 접두사는 지정된 이름과 일치하는 모든 클래스 경로 리소스를 가져온 다음(내부적으로는 기본적으로ClassLoader.getResources(...) 호출을 통해 이루어짐) 병합하여 최종 애플리케이션 컨텍스트 정의를 형성하도록 지정합니다.

  와일드카드 클래스 경로는 기본클래스 로더의 getResources() 메서드에 의존합니다. 오늘날 대부분의 애플리케이션 서버는 자체 ClassLoader구현을 제공하므로, 특히 jar 파일을 처리할 때 동작이 다를 수 있습니다. 클래스 경로*가 작동하는지 확인하는 간단한 테스트는 ClassLoader를 사용하여 클래스 경로에 있는 jar 내에서 파일을 로드하는 것입니다:getClass().getClassLoader().getResources("<someFileInsideTheJar>"). 이름이 같지만 서로 다른 두 위치에 있는 파일(예: 이름이 같고 경로가 같지만 클래스 경로의 다른 jar에 있는 파일)에 대해 이 테스트를 시도해 보세요. 부적절한 결과가 반환되는 경우 애플리케이션 서버 설명서에서 ClassLoader 동작에 영향을 줄 수 있는 설정을 확인하세요

클래스 경로*: 접두사를 나머지 위치 경로에 PathMatcher 패턴과 결합할 수도 있습니다(예: classpath*:META-INF/*-beans.xml). 이 경우 해결 전략은 매우 간단합니다: 와일드카드가 아닌 마지막 경로 세그먼트에서 ClassLoader.getResources() 호출을 사용하여 클래스 로더 계층 구조에서 일치하는 모든 리소스를 가져온 다음, 각 리소스에서 앞서 설명한 것과 동일한 PathMatcher 해결 전략이 와일드카드 하위 경로에 사용됩니다.

와일드카드와 관련된 기타 참고 사항

Classpath*: 를 Ant 스타일 패턴과 결합하면 실제 대상 파일이 파일 시스템에 존재하지 않는 한 패턴이 시작되기 전에 루트 디렉터리가 하나 이상 있어야만 안정적으로 작동한다는 점에 유의하세요. 즉,classpath*:*.xml과 같은 패턴은 jar 파일의 루트에서 파일을 검색하지 않고 확장된 디렉터리의 루트에서만 파일을 검색할 수 있습니다.

Spring의 클래스 경로 항목을 검색하는 기능은 JDK의ClassLoader.getResources() 메서드에서 비롯되며, 이 메서드는 빈 문자열(검색할 잠재적 루트)에 대한 파일 시스템 위치만 반환합니다. Spring은URLClassLoader 런타임 구성과 jar 파일의 java.class.path 매니페스트도 평가하지만, 이것이 이식 가능한 동작으로 이어진다고 보장되지는 않습니다.

 
클래스 경로 패키지를 검사하려면 클래스 경로에 해당 디렉토리 항목이 있어야 합니다. Ant로 JAR을 빌드할 때는 JAR 작업의 파일 전용스위치를 활성화하지 마세요. 또한 일부 환경에서는 보안 정책에 따라 클래스 경로 디렉터리가 노출되지 않을 수 있습니다(예: JDK 1.7.0_45 이상의 독립 실행형 애플리케이션(매니페스트에서 'Trusted-Library'를 설정해야 함).Stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources 참조).
JDK 9의 모듈 경로(직소)에서 Spring의 클래스 경로 검색은 일반적으로 예상대로 작동합니다. 여기에서도 리소스를 전용 디렉터리에 넣으면 앞서 언급한 jar 파일 루트 수준 검색으로 인한 이식성 문제를 피할 수 있습니다.

클래스 경로를 사용하는 Ant 스타일 패턴 : 검색할 루트 패키지가 여러 클래스 경로 위치에서 사용 가능한 경우 리소스가 일치하는 리소스를 찾지 못합니다. 다음 리소스 위치의 예를 생각해 보세요:

com/mycompany/package1/service-context.xml

이제 누군가가 해당 파일을 찾기 위해 사용할 수 있는 Ant 스타일의 경로를 생각해 보세요:

classpath:com/mycompany/**/service-context.xml

이러한 리소스는 클래스 경로의 한 위치에만 존재할 수 있지만, 앞의 예와 같은 경로를 사용하여 리소스를 확인하려고 하면 리졸버는 getResource("com/mycompany"); 에서 반환한 (첫 번째) URL에서 작동합니다. 이 기본 패키지 노드가 여러 클래스 로더 위치에 존재하는 경우 원하는 리소스가 처음 발견된 위치에 존재하지 않을 수 있습니다. 따라서 이러한 경우에는 동일한 Ant 스타일 패턴으로com. mycompany 기본 패키지가 포함된 모든 클래스 경로 위치를 검색하는 classpath* : :com/mycompany/**/service-context.xml을 사용하는 것을 선호해야 합니다.

FileSystemResource 주의 사항

파일시스템애플리케이션컨텍스트에 연결되지 않은 파일시스템리소스는 (즉, 파일시스템애플리케이션컨텍스트가 실제 리소스로더가 아닌 경우) 예상대로 절대 경로와 상대 경로를 처리합니다. 상대 경로는 현재 작업 디렉터리를 기준으로 하고 절대 경로는 파일시스템의 루트를 기준으로 합니다.

그러나 이전 버전과의 호환성(이전 버전과의 호환성)을 위해FileSystemApplicationContext가 리소스로더인 경우 변경됩니다.FileSystemApplicationContext는 연결된 모든 FileSystemResource 인스턴스가 선행 슬래시로 시작하든 아니든 모든 위치 경로를 상대 경로로 처리하도록 합니다. 실제로 이는 다음 예제가 동일하다는 것을 의미합니다:

ApplicationContext ctx =
	new FileSystemXmlApplicationContext("conf/context.xml");
ApplicationContext ctx =
	new FileSystemXmlApplicationContext("/conf/context.xml");

다음 예시도 동등합니다(한 경우는 상대적이고 다른 경우는 절대적이기 때문에 서로 다른 것이 합리적이지만):

FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("some/resource/path/myTemplate.txt");
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("/some/resource/path/myTemplate.txt");

실제로는 진정한 절대 파일 시스템 경로가 필요한 경우 FileSystemResource 또는 FileSystemXmlApplicationContext와 함께 절대 경로를 사용하지 말고 파일을 사용하여 UrlResource를 강제로 사용해야 합니다: URL 접두사를 사용해야 합니다. 다음 예제에서는 이를 수행하는 방법을 보여줍니다:

// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt");
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
ApplicationContext ctx =
	new FileSystemXmlApplicationContext("file:///conf/context.xml");


반응형
profile

while(1) work();

@유호건

❤️댓글은 언제나 힘이 됩니다❤️ 궁금한 점이나 잘못된 내용이 있다면 댓글로 남겨주세요.

검색 태그