リソース
この章では、Spring がリソースを処理する方法と、Spring でリソースを操作する方法について説明します。次のトピックが含まれます。
導入
残念ながら、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
を返します。リソース記述子をどこかに保持する必要がある場合、またはストリームを複数回読み取る必要がある場合は、使用しないでください。
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
オブジェクトに変換する戦略をまとめたものです。
接頭辞 | サンプル | 説明 |
---|---|---|
クラスパス: |
| クラスパスからロードされます。 |
ファイル: |
| ファイルシステムから |
https: |
|
|
(なし) |
| 基礎となる |
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
ユーティリティを使用して照合される)を含む場合もあります。後者はどちらも事実上ワイルドカードです。
標準の |
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
として使用されるため、リソースは、アプリケーションコンテキストの正確な型に応じて、ClassPathResource
、FileSystemResource
、ServletContextResource
を介してロードされます。
特定の 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 タスクの JDK 9 のモジュールパス(Jigsaw)では、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")