Оболочка InputStream, которая закрывает поток после завершения чтения - PullRequest
0 голосов
/ 12 июня 2018

Я столкнулся с некоторыми проблемами в проекте с Spring и Hibernate, когда поток, передаваемый Blob, не закрыт.

Blob blob = Hibernate.getLobCreator(currentSession).createBlob(inputStream, size);

Я не могу использовать такие вещи, как try with resources, поскольку поток читается только послетранзакция совершается.Я попытался закрыть поток с помощью hibernate @PostPersist.Он работает в персистентных ситуациях, но вызывает проблемы с Blob, уже освобожденным при CascadeType.MERGE сценариях.

Один из моих друзей предложил хакерский способ справиться с этим.По сути, его идея заключалась в том, чтобы написать оболочку, которая закрывает поток после завершения чтения.

import java.io.IOException;
import java.io.InputStream;

public class SelfClosingInputStream extends InputStream {

    private InputStream inputStream;

    public SelfClosingInputStream(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    @Override
    public int read() throws IOException {
        try {
            int val = this.inputStream.read();
            if (val != -1) {
                return val;
            } else {
                this.inputStream.close();
                return -1;
            }
        } catch (Exception e) {
            this.inputStream.close();
            throw e;
        }
    }
}

Я провел простой тест, и он работает.Я понимаю, что при проверке if может возникнуть проблема с производительностью.Однако я думаю, что в этом есть и другие предостережения.Может кто-то пролить свет на эти?

Blob blob = Hibernate.getLobCreator(currentSession).createBlob(new SelfClosingInputStream(inputStream), size);

PS: я уже опубликовал это здесь при проверке кода, но получил очень мало ответов.Отсюда следует репостинг с некоторыми обновлениями.

ОБНОВЛЕНИЕ:

Получено много отзывов об обзоре кода.Этот ответ , кажется, дает наиболее правильный способ сделать это.

Далее https://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/input/AutoCloseInputStream.html дает аналогичную реализацию.

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

Вы уверены, что поток не освобожден?Потому что, глядя на код BlobProxy, когда вы (или Hibernate) выпускаете большой двоичный объект, вызывающий Blob#free() через реализацию BlobProxy, выполняется InputStream#close(), и ваш поток должен быть правильно закрыт.

0 голосов
/ 12 июня 2018
public int read()  throws IOException {
    try {
        this.inputStream.read();
        if (val != -1) {
            return val;
        } else {
            this.inputStream.close();
            return -1;
        }
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("Something is wrong!");
    } finally {
    try {
            if (this.inputStream != null) {
            this.inputStreamObj.close();
            }
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
}

Вы должны принудительно установить close() с блоком finally, если this.inputStream не равно нулю.

...