Java - SMTP Transporter требует, чтобы SocketOutputStream открывался бесконечно - PullRequest
0 голосов
/ 29 августа 2018

Во время работы по рефакторингу я обнаружил, что если я закрою свой выходной поток с помощью «try-with-resources» - я всегда получаю MessagingException из Java-SMTPTransport. Всегда жалуется, что розетка была закрыта.

Код, который я определил, чтобы иметь проблемы, таков:

try (LineOutputStream los = new LineOutputStream(os);) {
    los.writeln(signatureHeaderLine);
    Enumeration hdrLines = getNonMatchingHeaderLines(ignoreList);
    while (hdrLines.hasMoreElements()) {
        String notIgnoredLine = (String) hdrLines.nextElement();
        los.writeln(notIgnoredLine);
    }

    los.writeln();
    // Send signed mail to waiting DATA command
    os.write(osBody.toByteArray());
    os.flush();
} catch (MessagingException me) {
    // Deal with it
} catch (Exception e) {
    // Deal with it
}

Приведенный выше код является частью переопределения MimeMessage.writeTo(OutputStream, String[]) И проблема возникает, когда в конечном итоге вызываются файлы `IssueSendCommand 'и' sendCommand 'из SMTPTransport .

Так значит ли это, что мои розетки должны оставаться открытыми все время? Я знаю с нетехнической точки зрения, неправильно закрывать сокет, так как я буду писать через него сообщения. Но я пытался понять, не приведет ли это в будущем к утечке памяти.

С уважением,

1 Ответ

0 голосов
/ 29 августа 2018

Я считаю, что проблема возникает из-за того, что вы используете OutputStream os вне оператора try-with-resource.

Оператор try-with-resource гарантирует, что все инициализированные ресурсы AutoClosable будут закрыты после выполнения блока try. На данный момент com.sun.mail.util.LineOutputStream закрыто, также будет закрыто OutputStream os (переданное его конструктору). Любой доступ к os после оператора try-with-resource действует на уже закрытый OutputStream.

edit Существует исключение, когда OutputStream имеет метод close() без эффекта. Например, для ByteArrayOutputStream.

Закрытие ByteArrayOutputStream не имеет никакого эффекта. Методы в этом классе могут вызываться после закрытия потока без генерации исключения IOException.

фрагмент для демонстрации

private static void demoMethod(OutputStream os) throws IOException {
    try (LineOutputStream los = new LineOutputStream(os)) {
        los.writeln("signatureHeaderLine");
        los.writeln();
        os.write("foo".getBytes());
        System.out.println("within try-block");
    } catch (Exception e) {
        System.out.println(e);
    }
    os.write("bar".getBytes());
    System.out.println("after try-block");
}

вызов метода demoMethod с ByteArrayOutputStream

ByteArrayOutputStream os = new ByteArrayOutputStream();
demoMethod(os);

дает вывод

within try-block
after try-block

Таким образом, ByteArrayOutputStream может использоваться даже после вызова close() для него (который неявно вызывается LineOutputStream.close (), вызываемого кодом try-with-resource).

То же самое с FileOutputStream

FileOutputStream os = new FileOutputStream("/tmp/dummy.out");
demoMethod(os);

выдает исключение, потому что FileOutputStream был близок в конце оператора try-with-resource.

within try-block
Exception in thread "main" java.io.IOException: Stream Closed
    at java.base/java.io.FileOutputStream.writeBytes(Native Method)
    at java.base/java.io.FileOutputStream.write(FileOutputStream.java:342)
    at Main.demoMethod(Main.java:24)
    at Main.main(Main.java:12)
...