リソース

導入

残念ながら、Java の標準 java.net.URL クラスとさまざまな URL プレフィックスの標準ハンドラーは、低レベルのリソースへのすべてのアクセスには十分ではありません。例: クラスパスから取得する必要があるリソースや ServletContext に関連するリソースにアクセスするために使用できる標準化された URL 実装はありません。特殊化された URL プレフィックス (http: などのプリフィックス用の既存のハンドラーと同様) 用の新しいハンドラーを登録することは可能ですが、これは一般に非常に複雑であり、URL インターフェースには、指されているリソースの存在をチェックするメソッドなど、いくつかの望ましい機能がまだ欠落しています。

Resource インターフェース

org.springframework.core.io. パッケージにある Spring の Resource インターフェースは、低レベルのリソースへのアクセスを抽象化するためのより高性能なインターフェースとなることを目的としています。次のリストは、Resource インターフェースの概要を示しています。詳細については、Resource javadoc を参照してください。

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(): このリソースが実際に物理的な形で存在するかどうかを示す boolean を返します。

  • isOpen(): このリソースがオープンストリームのハンドルを表すかどうかを示す boolean を返します。true の場合、InputStream は複数回読み取ることができず、リソースリークを避けるために一度だけ読み取ってから閉じる必要があります。InputStreamResource を除き、すべての通常のリソース実装に対して false を返します。

  • getDescription(): このリソースの説明を返します。これは、リソースを操作する際のエラー出力に使用されます。多くの場合、これは完全修飾ファイル名またはリソースの実際の URL です。

他のメソッドを使用すると、リソースを表す実際の URL または File オブジェクトを取得できます(基礎となる実装に互換性があり、その機能をサポートしている場合)。

Resource インターフェースの一部の実装では、書き込みをサポートするリソースの拡張 WritableResource (Javadoc) インターフェースも実装されています。

Spring 自体は、リソースが必要な場合に多くのメソッドシグニチャーの引数型として、Resource 抽象を広範囲に使用します。一部の Spring API の他のメソッド (様々な ApplicationContext 実装のコンストラクターなど) は String を使用します。これは修飾されていない、または単純な形式で、そのコンテキスト実装に適した Resource を作成するために使用されます。また、String パス上の特別なプレフィックスを使用して、呼び出し側が特定の Resource 実装を作成して使用する必要があることを指定できます。

Resource インターフェースは Spring や Spring でよく使用されますが、コードが他のことを知らない、気にしない場合でも、リソースにアクセスするために、独自のコードでそれ自体を一般的なユーティリティクラスとして使用すると非常に便利です。Spring の一部。これはコードを Spring に結合しますが、実際にはこの小さなユーティリティクラスのセットにのみ結合します。これは、URL のより有能な代替として機能し、この目的で使用する他のライブラリと同等と見なすことができます。

Resource 抽象化は機能を置き換えません。可能な場合はラップします。例: UrlResource は URL をラップし、ラップされた URL を使用して作業を行います。

ビルトイン Resource 実装

Spring には、いくつかの組み込み Resource 実装が含まれています。

Spring で使用可能な Resource 実装の完全なリストについては、Resource javadoc の「すべての既知の実装クラス」セクションを参照してください。

UrlResource

UrlResource は java.net.URL をラップし、ファイル、HTTPS ターゲット、FTP ターゲットなど、通常は URL でアクセスできる任意のオブジェクトにアクセスするために使用できます。すべての URL には標準化された String 表現があり、適切な標準化されたプレフィックスを使用して、ある URL 型を別の URL 型から示します。これには、ファイルシステムパスにアクセスするための file:、HTTPS プロトコルを介してリソースにアクセスするための https:、FTP を介してリソースにアクセスするための ftp: などが含まれます。

UrlResource は、UrlResource コンストラクターを明示的に使用して Java コードによって作成されますが、パスを表すことを目的とした String 引数をとる API メソッドを呼び出すと、暗黙的に作成されることがよくあります。後者の場合、JavaBeans PropertyEditor は、最終的にどの型の Resource を作成するかを決定します。パス文字列に既知の(プロパティエディター、つまり)プレフィックス(classpath: など)が含まれている場合、そのプレフィックスに適切な特殊な Resource が作成されます。ただし、プレフィックスを認識しない場合は、文字列が標準の URL 文字列であると見なし、UrlResource を作成します。

ClassPathResource

このクラスは、クラスパスから取得するリソースを表します。スレッドコンテキストクラスローダー、特定のクラスローダー、リソースの読み込みに特定のクラスのいずれかを使用します。

この Resource 実装は、クラスパスリソースがファイルシステムに存在するが、jar に存在し、(サーブレットエンジンまたは環境が何であっても)ファイルシステムに展開されていないクラスパスリソースではない場合、java.io.File としての解決をサポートします。これに対処するために、さまざまな Resource 実装は、常に java.net.URL としての解決をサポートします。

ClassPathResource は、明示的に ClassPathResource コンストラクターを使用して Java コードによって作成されますが、パスを表すための String 引数を取る API メソッドを呼び出すと暗黙的に作成されることがよくあります。後者の場合、JavaBeans PropertyEditor はストリングパス上の特別なプレフィックス classpath を認識し、その場合 ClassPathResource を作成します。

FileSystemResource

これは、java.io.File ハンドルの Resource 実装です。また、java.nio.file.Path ハンドルをサポートし、Spring の標準の文字列ベースのパス変換を適用しますが、java.nio.file.Files API を介してすべての操作を実行します。純粋な java.nio.path.Path ベースのサポートの場合は、代わりに PathResource を使用してください。FileSystemResource は、File および URL としての解決をサポートします。

PathResource

これは、java.nio.file.Path ハンドルの Resource 実装であり、Path API を介してすべての操作と変換を実行します。File および URL としての解決をサポートし、拡張 WritableResource インターフェースも実装します。PathResource は、createRelative の動作が異なる FileSystemResource の純粋な java.nio.path.Path ベースの代替です。

ServletContextResource

これは、関連する Web アプリケーションのルートディレクトリ内の相対パスを解釈する ServletContext リソースの Resource 実装です。

常にストリームアクセスと URL アクセスをサポートしますが、Web アプリケーションアーカイブが展開され、リソースが物理的にファイルシステム上にある場合にのみ java.io.File アクセスを許可します。拡張されてファイルシステム上にあるか、JAR またはデータベースのような他の場所(考えられる)から直接アクセスされるかどうかは、実際にはサーブレットコンテナーに依存します。

InputStreamResource

InputStreamResource は、指定された InputStream の Resource 実装です。特定の Resource 実装が適用できない場合にのみ使用してください。特に、可能な場合は、ByteArrayResource またはファイルベースの Resource 実装のいずれかを優先してください。

他の Resource 実装とは対照的に、これはすでに開かれているリソースの記述子です。isOpen() から true を返します。リソース記述子をどこかに保持する必要がある場合、またはストリームを複数回読み取る必要がある場合は、使用しないでください。

ByteArrayResource

これは、指定されたバイト配列の Resource 実装です。指定されたバイト配列の ByteArrayInputStream を作成します。

これは、使い捨ての InputStreamResource に頼ることなく、任意のバイト配列からコンテンツをロードできます。

ResourceLoader インターフェース

ResourceLoader インターフェースは、Resource インスタンスを返す(ロードする)オブジェクトによって実装されることを意図しています。次のリストは、ResourceLoader インターフェース定義を示しています。

public interface ResourceLoader {

	Resource getResource(String location);

	ClassLoader getClassLoader();
}

すべてのアプリケーションコンテキストは、ResourceLoader インターフェースを実装します。すべてのアプリケーションコンテキストを使用して Resource インスタンスを取得できます。

特定のアプリケーションコンテキストで getResource() を呼び出し、指定した場所のパスに特定のプレフィックスがない場合、その特定のアプリケーションコンテキストに適した Resource 型が返されます。例: 次のコードスニペットが ClassPathXmlApplicationContext インスタンスに対して実行されたと想定します。

  • Java

  • Kotlin

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

ClassPathXmlApplicationContext に対して、そのコードは ClassPathResource を返します。同じメソッドが FileSystemXmlApplicationContext インスタンスに対して実行された場合、FileSystemResource が返されます。WebApplicationContext の場合、ServletContextResource を返します。同様に、各コンテキストに適切なオブジェクトを返します。

その結果、特定のアプリケーションコンテキストに適した方法でリソースをロードできます。

一方、次の例に示すように、特殊な classpath: プレフィックスを指定することにより、アプリケーションコンテキスト型に関係なく、ClassPathResource を強制的に使用することもできます。

  • Java

  • Kotlin

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

同様に、標準の java.net.URL プレフィックスのいずれかを指定することにより、UrlResource を強制的に使用できます。次の例では、file および https プレフィックスを使用しています。

  • Java

  • Kotlin

Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
val template = ctx.getResource("file:///some/resource/path/myTemplate.txt")
  • Java

  • Kotlin

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

次の表は、String オブジェクトを Resource オブジェクトに変換する戦略をまとめたものです。

表 1: リソース文字列
接頭辞 サンプル 説明

クラスパス:

classpath:com/myapp/config.xml

クラスパスからロードされます。

ファイル:

file:///data/config.xml

ファイルシステムから URL としてロードされます。FileSystemResource 警告も参照してください。

https:

https://myserver/logo.png

URL としてロードされます。

(なし)

/data/config.xml

基礎となる ApplicationContext に依存します。

ResourcePatternResolver インターフェース

ResourcePatternResolver インターフェースは ResourceLoader インターフェースの拡張であり、ロケーションパターン(たとえば、Ant スタイルのパスパターン)を Resource オブジェクトに解決するための戦略を定義します。

public interface ResourcePatternResolver extends ResourceLoader {

	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

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

上記のように、このインターフェースは、クラスパスから一致するすべてのリソースに対して特別な classpath*: リソースプレフィックスも定義します。この場合、リソースの場所はプレースホルダーのないパスであると想定されていることに注意してください(たとえば、classpath*:/config/beans.xml)。クラスパス内の JAR ファイルまたは異なるディレクトリには、同じパスと同じ名前の複数のファイルを含めることができます。classpath*: リソースプレフィックスを使用したワイルドカードサポートの詳細については、アプリケーションコンテキストコンストラクターリソースパスのワイルドカードとそのサブセクションを参照してください。

渡された ResourceLoader (たとえば、ResourceLoaderAware セマンティクスを介して提供されるもの)は、この拡張インターフェースも実装しているかどうかを確認できます。

PathMatchingResourcePatternResolver は、ApplicationContext の外部で使用できるスタンドアロンの実装であり、Resource[] Bean プロパティを設定するために ResourceArrayPropertyEditor によっても使用されます。PathMatchingResourcePatternResolver は、指定されたリソースロケーションパスを 1 つ以上の一致する Resource オブジェクトに解決できます。ソースパスは、ターゲット Resource への 1 対 1 のマッピングを持つ単純なパスである場合もあれば、特別な classpath*: プレフィックスや内部 Ant スタイルの正規表現(Spring の org.springframework.util.AntPathMatcher ユーティリティを使用して照合される)を含む場合もあります。後者はどちらも事実上ワイルドカードです。

標準の ApplicationContext のデフォルトの ResourceLoader は、実際には ResourcePatternResolver インターフェースを実装する PathMatchingResourcePatternResolver のインスタンスです。同じことが ApplicationContext インスタンス自体にも当てはまります。ApplicationContext インスタンス自体も ResourcePatternResolver インターフェースを実装し、デフォルトの PathMatchingResourcePatternResolver に委譲します。

ResourceLoaderAware インターフェース

ResourceLoaderAware インターフェースは、ResourceLoader 参照が提供されることを期待するコンポーネントを識別する特別なコールバックインターフェースです。次のリストは、ResourceLoaderAware インターフェースの定義を示しています。

public interface ResourceLoaderAware {

	void setResourceLoader(ResourceLoader resourceLoader);
}

クラスが ResourceLoaderAware を実装し、アプリケーションコンテキストに(Spring 管理の Bean として)デプロイされると、アプリケーションコンテキストによって ResourceLoaderAware として認識されます。次に、アプリケーションコンテキストは setResourceLoader(ResourceLoader) を呼び出し、自身を引数として提供します(Spring のすべてのアプリケーションコンテキストが ResourceLoader インターフェースを実装することを思い出してください)。

ApplicationContext は ResourceLoader であるため、Bean は ApplicationContextAware インターフェースを実装し、提供されたアプリケーションコンテキストを直接使用してリソースをロードすることもできます。ただし、一般的には、必要な場合は専用の ResourceLoader インターフェースを使用することをお勧めします。コードは、Spring ApplicationContext インターフェース全体ではなく、リソースローディングインターフェース(ユーティリティインターフェースと見なすことができます)にのみ結合されます。

アプリケーションコンポーネントでは、ResourceLoaderAware インターフェースを実装する代わりに、ResourceLoader のオートワイヤーに依存することもできます。従来の constructor および byType オートワイヤーモード(オートワイヤーのコラボレーターで説明)は、コンストラクター引数または setter メソッドパラメーターのいずれかにそれぞれ ResourceLoader を提供できます。柔軟性を高めるために(フィールドと複数のパラメーターメソッドをオートワイヤーする機能を含む)、アノテーションベースのオートワイヤー機能の使用を検討してください。その場合、ResourceLoader は、問題のフィールド、コンストラクター、メソッドが @Autowired アノテーションを持っている限り、ResourceLoader 型を予期するフィールド、コンストラクター引数、メソッドパラメーターにオートワイヤーされます。詳細については、@Autowired を使用するを参照してください。

ワイルドカードを含む、または特別な classpath*: リソースプレフィックスを使用するリソースパスの 1 つ以上の Resource オブジェクトをロードするには、ResourceLoader の代わりに ResourcePatternResolver のインスタンスをアプリケーションコンポーネントにオートワイヤーすることを検討してください。

依存関係としてのリソース

Bean 自体が何らかの動的プロセスを介してリソースパスを決定して提供する場合、Bean が ResourceLoader または ResourcePatternResolver インターフェースを使用してリソースをロードすることはおそらく理にかなっています。例: 必要な特定のリソースがユーザーのロールに依存する、ある種のテンプレートのロードを検討してください。リソースが静的である場合は、ResourceLoader インターフェース(または ResourcePatternResolver インターフェース)の使用を完全に排除し、Bean に必要な Resource プロパティを公開させ、それらが注入されることを期待することは理にかなっています。

これらのプロパティを挿入するのが簡単なのは、すべてのアプリケーションコンテキストが登録され、String パスを Resource オブジェクトに変換できる特別な JavaBeans PropertyEditor を使用することです。例: 次の MyBean クラスには、型 Resource の template プロパティがあります。

  • Java

  • Kotlin

public class MyBean {

	private Resource template;

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

	// ...
}
class MyBean(var template: Resource)

次の例に示すように、XML 構成ファイルでは、template プロパティをそのリソースの単純な文字列で構成できます。

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

リソースパスにはプレフィックスがないことに注意してください。アプリケーションコンテキスト自体が ResourceLoader として使用されるため、リソースは、アプリケーションコンテキストの正確な型に応じて、ClassPathResourceFileSystemResourceServletContextResource を介してロードされます。

特定の Resource 型を強制的に使用する必要がある場合は、プレフィックスを使用できます。次の 2 つの例は、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 Environment で使用できるようになっているプロパティファイルに格納できます(環境の抽象化を参照)。テンプレートパスは、プロパティプレースホルダーを使用して @Value アノテーションを介して参照できます(@Value の使用を参照)。Spring は、テンプレートパスの値を文字列として取得し、特別な PropertyEditor は、文字列を Resource オブジェクトに変換して、MyBean コンストラクターに挿入します。次の例は、これを実現する方法を示しています。

  • Java

  • Kotlin

@Component
public class MyBean {

	private final Resource template;

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

	// ...
}
@Component
class MyBean(@Value("\${template.path}") private val template: Resource)

クラスパス内の複数の場所(クラスパス内の複数の jar など)の同じパスで検出された複数のテンプレートをサポートする場合は、特別な classpath*: プレフィックスとワイルドカードを使用して templates.path キーを classpath*:/config/templates/*.txt として定義できます。MyBean クラスを次のように再定義すると、Spring は、テンプレートパスパターンを、MyBean コンストラクターに挿入できる Resource オブジェクトの配列に変換します。

  • Java

  • Kotlin

@Component
public class MyBean {

	private final Resource[] templates;

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

	// ...
}
@Component
class MyBean(@Value("\${templates.path}") private val templates: Resource[])

アプリケーションコンテキストとリソースパス

このセクションでは、XML で機能するショートカット、ワイルドカードの使用方法、その他の詳細など、リソースを使用してアプリケーションコンテキストを作成する方法について説明します。

アプリケーションコンテキストの構築

(特定のアプリケーションコンテキスト型の)アプリケーションコンテキストコンストラクターは、通常、コンテキストの定義を構成する XML ファイルなど、リソースのロケーションパスとして文字列または文字列の配列を取ります。

そのようなロケーションパスにプレフィックスがない場合、そのパスから作成され、Bean 定義のロードに使用される特定の Resource 型は、特定のアプリケーションコンテキストに依存し、適切です。例: ClassPathXmlApplicationContext を作成する次の例を検討してください。

  • Java

  • Kotlin

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

ClassPathResource が使用されるため、Bean 定義はクラスパスからロードされます。ただし、FileSystemXmlApplicationContext を作成する次の例を検討してください。

  • Java

  • Kotlin

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

これで、Bean 定義がファイルシステムの場所からロードされます(この場合、現在の作業ディレクトリを基準にしています)。

ロケーションパスで特別な classpath プレフィックスまたは標準の URL プレフィックスを使用すると、Bean 定義をロードするために作成されたデフォルト型の Resource が上書きされることに注意してください。次の例を考えてみましょう。

  • Java

  • Kotlin

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

FileSystemXmlApplicationContext を使用すると、クラスパスから Bean 定義がロードされます。ただし、まだ FileSystemXmlApplicationContext です。その後 ResourceLoader として使用される場合、接頭辞のないパスはファイルシステムパスとして扱われます。

ClassPathXmlApplicationContext インスタンスの構築 — ショートカット

ClassPathXmlApplicationContext は、便利なインスタンス化を可能にするために、多数のコンストラクターを公開しています。基本的な考え方は、XML ファイル自体のファイル名のみを含む(先頭のパス情報を含まない)文字列配列のみを提供し、Class も提供できるということです。次に、ClassPathXmlApplicationContext は、提供されたクラスからパス情報を取得します。

次のディレクトリレイアウトを検討してください。

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

次の例は、services.xml および repositories.xml (クラスパス上にある)という名前のファイルで定義された Bean で構成される ClassPathXmlApplicationContext インスタンスをインスタンス化する方法を示しています。

  • Java

  • Kotlin

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

さまざまなコンストラクターの詳細については、ClassPathXmlApplicationContext javadoc を参照してください。

アプリケーションコンテキストコンストラクターリソースパスのワイルドカード

アプリケーションコンテキストコンストラクター値のリソースパスは、(前に示したように)単純なパスであり、それぞれがターゲット Resource への 1 対 1 のマッピングを持っているか、、特別な classpath*: プレフィックスまたは内部 Ant スタイルパターンを含むことができます(Spring の PathMatcher ユーティリティを使用して一致します)。後者はどちらも事実上ワイルドカードです。

このメカニズムの用途の 1 つは、コンポーネントスタイルのアプリケーションアセンブリを実行する必要がある場合です。すべてのコンポーネントはコンテキスト定義フラグメントを既知のロケーションパスに公開でき、最終的なアプリケーションコンテキストが classpath*: で始まる同じパスを使用して作成されると、すべてのコンポーネントフラグメントが自動的に取得されます。

このワイルドカードは、アプリケーションコンテキストコンストラクター(または PathMatcher ユーティリティクラス階層を直接使用する場合)でのリソースパスの使用に固有であり、構築時に解決されることに注意してください。Resource 型自体とは関係ありません。リソースは一度に 1 つのリソースのみを指すため、classpath*: プレフィックスを使用して実際の Resource を構築することはできません。

Ant スタイルのパターン

次の例に示すように、パスの場所には Ant スタイルのパターンを含めることができます。

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

パスの場所に Ant スタイルのパターンが含まれている場合、リゾルバーはより複雑な手順に従ってワイルドカードの解決を試みます。最後の非ワイルドカードセグメントまでのパスに対して Resource を生成し、そこから URL を取得します。この URL が jar: URL またはコンテナー固有のバリアント(WebLogic の zip:、WebSphere の wsjar など)ではない場合、java.io.File がそこから取得され、ファイルシステムを走査してワイルドカードを解決するために使用されます。jar URL の場合、リゾルバーはそこから java.net.JarURLConnection を取得するか、jar URL を手動で解析してから、jar ファイルの内容を走査してワイルドカードを解決します。

移植性への影響

指定されたパスがすでに file URL である場合(ベース ResourceLoader がファイルシステム 1 であるために暗黙的に、または明示的に)、ワイルドカードは完全に移植可能な方法で機能することが保証されます。

指定されたパスが classpath の場所である場合、リゾルバーは Classloader.getResource() 呼び出しを行うことにより、最後の非ワイルドカードパスセグメント URL を取得する必要があります。これはパスの単なるノードであるため(最後のファイルではありません)、実際には(ClassLoader javadoc では)この場合に返される URL の種類は正確には定義されていません。実際には、これは常にディレクトリ(クラスパスリソースがファイルシステムの場所に解決される)またはある種の jar URL(クラスパスリソースが jar の場所に解決される)を表す java.io.File です。それでも、この操作には移植性の懸念があります。

jar URL が最後の非ワイルドカードセグメントについて取得された場合、リゾルバーは、jar から java.net.JarURLConnection を取得するか、jar URL を手動で解析して、jar の内容を調べてワイルドカードを解決できる必要があります。これはほとんどの環境で機能しますが、他の環境では失敗します。jar からのリソースのワイルドカード解決は、依存する前に特定の環境で徹底的にテストすることを強くお勧めします。

classpath*: プレフィックス

XML ベースのアプリケーションコンテキストを構築するとき、次の例に示すように、ロケーション文字列は特別な classpath*: プレフィックスを使用する場合があります。

  • Java

  • Kotlin

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

この特別なプレフィックスは、指定された名前に一致するすべてのクラスパスリソースを取得し(内部的には、本質的に ClassLoader.getResources(…​) の呼び出しによって発生)、その後、マージして最終的なアプリケーションコンテキスト定義を形成する必要があることを指定します。

ワイルドカードクラスパスは、基になる ClassLoader の getResources() メソッドに依存しています。最近のほとんどのアプリケーションサーバーは独自の ClassLoader 実装を提供しているため、特に jar ファイルを処理する場合は、動作が異なる可能性があります。classpath* が機能するかどうかを確認する簡単なテストは、ClassLoader を使用して、クラスパス getClass().getClassLoader().getResources("<someFileInsideTheJar>") の jar 内からファイルをロードすることです。同じ名前で 2 つの異なる場所にあるファイル(たとえば、同じ名前で同じパスであるがクラスパス上の異なる jar にあるファイル)でこのテストを試してください。不適切な結果が返された場合は、アプリケーションサーバーのドキュメントで ClassLoader の動作に影響を与える可能性のある設定を確認してください。

また、ロケーションパスの残りの部分で、classpath*: プレフィックスと PathMatcher パターンを組み合わせることができます(たとえば、classpath*:META-INF/*-beans.xml)。この場合、解決戦略は非常に簡単です: ClassLoader.getResources() 呼び出しを最後の非ワイルドカードパスセグメントで使用して、クラスローダー階層内のすべての一致するリソースを取得し、次に各リソースから、前述の同じ PathMatcher 解決戦略を取得します。ワイルドカードサブパスに使用されます。

ワイルドカードに関するその他の注意事項

classpath* は、Ant スタイルのパターンと組み合わせると、実際のターゲットファイルがファイルシステムに存在しない限り、パターンが開始する前に少なくとも 1 つのルートディレクトリでのみ確実に動作することに注意してください。つまり、classpath*:*.xml などのパターンは、jar ファイルのルートからではなく、展開されたディレクトリのルートからのみファイルを取得する可能性があります。

Spring のクラスパスエントリを取得する機能は、JDK の ClassLoader.getResources() メソッドに由来します。このメソッドは、空の文字列(検索する潜在的なルートを示す)のファイルシステムの場所のみを返します。Spring は URLClassLoader ランタイム構成と jar ファイル内の java.class.path マニフェストも評価しますが、これは移植性のある動作を保証するものではありません。

クラスパスパッケージをスキャンするには、クラスパスに対応するディレクトリエントリが存在する必要があります。Ant を使用して JAR を作成する場合は、JAR タスクの files-only スイッチをアクティブにしないでください。また、一部の環境では、セキュリティポリシーに基づいてクラスパスディレクトリが公開されない場合があります。たとえば、JDK 1.7.0_45 以降のスタンドアロンアプリケーション(マニフェストに "Trusted-Library" を設定する必要があります。stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources (英語) を参照)。

モジュールパス (Java モジュールシステム) では、Spring のクラスパススキャンは、通常、期待どおりに動作します。ここでも、リソースを専用のディレクトリに配置することを強くお勧めします。これにより、jar ファイルのルートレベルを検索する場合に発生する前述の移植性の問題を回避できます。

検索するルートパッケージが複数のクラスパスの場所で利用できる場合、classpath: リソースを使用する Ant スタイルのパターンが一致するリソースを見つけることは保証されません。リソースの場所の次の例について考えてみます。

com/mycompany/package1/service-context.xml

次に、誰かがそのファイルを見つけるために使用する Ant スタイルのパスを考えてみましょう。

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

このようなリソースは、クラスパス内の 1 つの場所にのみ存在する可能性がありますが、前の例のようなパスを使用してリソースを解決しようとすると、リゾルバーは getResource("com/mycompany"); によって返される(最初の)URL を処理します。この基本パッケージノードが複数の ClassLoader の場所に存在する場合、最初に見つかった場所に目的のリソースが存在しない可能性があります。このような場合は、同じ Ant スタイルのパターンで classpath*: を使用することをお勧めします。これにより、com.mycompany 基本パッケージ classpath*:com/mycompany/**/service-context.xml を含むすべてのクラスパスの場所が検索されます。

FileSystemResource 警告

FileSystemApplicationContext に接続されていない FileSystemResource (つまり、FileSystemApplicationContext が実際の ResourceLoader ではない場合)は、予想どおりに絶対パスと相対パスを処理します。相対パスは現在の作業ディレクトリからの相対パスですが、絶対パスはファイルシステムのルートからの相対パスです。

ただし、下位互換性(履歴)の理由により、FileSystemApplicationContext が ResourceLoader の場合、これは変更されます。FileSystemApplicationContext は、接続されているすべての FileSystemResource インスタンスに、先頭のスラッシュで始まるかどうかに関係なく、すべてのロケーションパスを強制的に相対パスとして処理させます。実際には、これは次の例が同等であることを意味します。

  • Java

  • Kotlin

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

  • Kotlin

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

次の例も同等です(1 つのケースは相対的で、もう 1 つのケースは絶対的であるため、それらが異なることは理にかなっていますが)。

  • Java

  • Kotlin

FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("some/resource/path/myTemplate.txt");
val ctx: FileSystemXmlApplicationContext = ...
ctx.getResource("some/resource/path/myTemplate.txt")
  • Java

  • Kotlin

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

実際には、真の絶対ファイルシステムパスが必要な場合は、FileSystemResource または FileSystemXmlApplicationContext での絶対パスの使用を避け、file: URL プレフィックスを使用して UrlResource の使用を強制する必要があります。次の例は、その方法を示しています。

  • Java

  • Kotlin

// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt");
// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt")
  • Java

  • Kotlin

// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
ApplicationContext ctx =
	new FileSystemXmlApplicationContext("file:///conf/context.xml");
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
val ctx = FileSystemXmlApplicationContext("file:///conf/context.xml")