Web アプリの画像アップロード機能に取り組んでいますが、apache commons fileupload の「FileCleaningTracker」で奇妙な問題が発生しています。インスタンス変数 FileCleaningTracker を持つ ImageUploadService があり、次に DiskFileItemFactory のインスタンスを作成し、FileCleaningTracker を参照するアップロード メソッドがあります。アップロード メソッドが正常に完了した後、DiskFileItemFactory の FileCleaningTracker を null に設定するので、DiskFileItemFactory が期待されます。がガベージ コレクションされると、FileCleaningTracker の PhantomReference の基になるサブクラスに通知されるため、DiskFileItemFactory が作成した一時ファイルを削除します。
しかし、それは、アップロード メソッドの最後で DiskFileItemFactory を null にして System.gc() を呼び出すまでは起こりません (DiskFileItemFactory を null にするだけでは役に立ちません)。これは私には非常に奇妙に思えます。これが私のコードです:
@Override
public void upload(final HttpServletRequest request) {
ValidateUtils.checkNotNull(request, "upload request");
final File tmp = new File(this.tempFolder);
if (!tmp.exists()) {
tmp.mkdir();
}
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory(this.sizeThreshold, tmp);
fileItemFactory.setFileCleaningTracker(this.fileCleaningTracker);
ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
List items;
try {
items = uploadHandler.parseRequest(request);
} catch (final FileUploadException e) {
throw new ImageUploadServiceException("Error parsing the http servlet request for image upload.", e);
}
final Iterator it = items.iterator();
while (it.hasNext()) {
final DiskFileItem item = (DiskFileItem) it.next();
if (item.isFormField()) {
// log message
} else {
final String fileName = item.getName();
final File destination = this.createFileForUpload(fileName, this.uploadFolder);
FileChannel outChannel;
try {
outChannel = new FileOutputStream(destination).getChannel();
} catch (final FileNotFoundException e) {
throw new ImageUploadServiceException(e);
}
FileChannel inChannel = null;
try {
inChannel = new FileInputStream(item.getStoreLocation()).getChannel();
outChannel.transferFrom(inChannel, 0, item.getSize());
} catch (final IOException e) {
throw new ImageUploadServiceException(String.format("Error uploading image to '%s/%s'.", this.uploadFolder, destination.getName()), e);
} finally {
IOUtils.closeChannel(inChannel);
IOUtils.closeChannel(outChannel);
}
}
}
fileItemFactory.setFileCleaningTracker(null);
}
上記のコードにより、すべてのアップロードで一時フォルダーにファイルが作成されますが、「fileCleaningTracker」によって最後に削除されません。おそらく、DiskFileItemFactory インスタンスがガベージ コレクションされていないためです (そうすべきではない理由がわかりませんでした)。または、GC されているが、fileCleaningTracker の PhantomReference から通知されていない (PhantomReference の信頼性は?)
10 分待ったが、ファイルはまだそこにあるので、GC が実行されていないためではないはずです。そして例外はありません。
次のコードを追加すると、アップロード後に毎回一時ファイルが削除されます。
fileItemFactory = null;
System.gc();
System.gc() への明示的な呼び出しなしで fileItemFactory が GC されることを期待するので、これは私には非常に奇妙に見えます。
任意の入力をいただければ幸いです。
ありがとうございました。