org.springframework.core.io.Resource は、ファイル、クラスパスエントリ、URL、
サーブレットコンテキスト、バイト配列、すでに開かれたストリームなどに存在し得る
コンテンツを、Spring API から扱う 1 つのハンドルとして提供します。この抽象化が
記述するのはアクセス能力であり、すべてのリソースをシーク可能、反復可能、書き込み
可能、またはファイルを基盤とするものにするわけではありません。
Resource の契約
#
Resource は InputStreamSource を拡張します。基本操作は getInputStream() であり、
exists()、isReadable()、isOpen()、isFile()、contentLength()、lastModified()、
getDescription() などのメソッドが能力またはメタデータを公開します。
重要な実装には次があります。
ClassPathResourcefor class-loader or class-relative entries;FileSystemResourceandPathResourcefor filesystem content;UrlResourcefor URLs supported by the JVM;ServletContextResourcefor web-application paths;ByteArrayResourcefor repeatable in-memory bytes; andInputStreamResourcefor an already-open, normally single-use stream.
呼び出し側は getInputStream() が返すすべてのストリームを所有し、閉じなければ
なりません。isOpen() は特に重要です。InputStreamResource は開かれたハンドルを
ラップするため安全に繰り返し読めませんが、ファイルおよびバイト配列のリソースは
呼び出しごとに新しいストリームを開けます。
ロードと相対解決 #
ResourceLoader.getResource(String) はロケーションを 1 つのリソースに変換します。
すべての ApplicationContext はリソースローダーです。プレフィックスで明示的な
意味を選択できます。
classpath:com/example/report.htmlselects a classpath resource.file:/srv/app/report.htmlselects a filesystem URL.https://example.net/schema.jsonselects a URL resource.
プレフィックスのないロケーションはコンテキスト相対です。
ClassPathXmlApplicationContext はクラスパスロケーションとして、
FileSystemXmlApplicationContext はファイルシステムロケーションとして、Web
アプリケーションコンテキストはサーブレットコンテキストロケーションとして解釈します。
ライブラリコードは 1 つのデフォルトを仮定せず、Resource または ResourceLoader
を要求します。
ResourcePatternResolver はロケーションパターンと複数一致にロード機能を拡張します。
classpath*: は一致するすべてのクラスパスルートを検索します。Ant 形式のワイルド
カードはパターン解決で適用され、単一リソースの ResourceLoader 契約では適用
されません。
リソースを注入する #
Spring は周囲のアプリケーションコンテキストをローダーとして、ロケーション文字列を
Resource に変換できます。
@Component
final class ReportRenderer {
private final Resource template;
ReportRenderer(@Value("${report.template:classpath:reports/daily.html}")
Resource template) {
this.template = template;
}
}コンストラクター注入により依存関係が明確になり、テストから ByteArrayResource を
渡せます。操作ごとにロケーションが変わる場合は ResourceLoader を注入し、アプリ
ケーションが意図的に複数一致を受け入れる場合だけ Resource[] または
ResourcePatternResolver を注入します。
存在、反復性、書き込み #
exists() は確認であり予約ではありません。開く前にコンテンツが消えることがあります。
アクセスの正しさが重要な場合は、リソースを開いて発生する IOException を処理する
ことを優先します。メタデータ操作にも I/O が必要な場合があり、リモート URL は遅い
か利用できない可能性があります。
WritableResource は isWritable() と getOutputStream() を追加します。
FileSystemResource と PathResource はこれを実装しますが、パッケージ化された JAR
内のクラスパスリソースは実装しません。書き込みを行うコードはロケーション文字列に
基づいてダウンキャストせず、WritableResource を要求します。
反復性は実装に依存します。2 回のパスを必要とするパーサーは、明示的なサイズ制限を
設けて、一度しか使えないリソースを ByteArrayResource にバッファーできます。
リソースの所有権を曖昧にしないため、API はストリームを一度だけ開くのか、再度開く
のか、保持するのか、閉じるのかを文書化します。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)