В сервлетах Java можно получить доступ к телу ответа через response.getOutputStream()
или response.getWriter()
. Следует ли позвонить .close()
по этому OutputStream
поводу после того, как было написано?
С одной стороны, есть блоховский призыв всегда закрывать OutputStream
s. С другой стороны, я не думаю, что в этом случае есть базовый ресурс, который нужно закрыть. Открытие / закрытие сокетов управляется на уровне HTTP, чтобы разрешить такие вещи, как постоянные соединения и тому подобное.
java
servlets
outputstream
Стивен Хьювиг
источник
источник
close()
, который ничего не делает. Что вы должны сделать , это близко каждый закрываемой ресурс.Ответы:
Обычно вам не следует закрывать поток. Контейнер сервлета автоматически закроет поток после завершения работы сервлета в рамках жизненного цикла запроса сервлета.
Например, если вы закроете поток, он будет недоступен, если вы реализовали фильтр .
Сказав все это, если вы закроете его, ничего плохого не произойдет, если вы не попытаетесь использовать его снова.
РЕДАКТИРОВАТЬ: еще одна ссылка на фильтр
EDIT2: adrian.tarau верен в том, что если вы хотите изменить ответ после того, как сервлет сделал свое дело, вы должны создать оболочку, расширяющую HttpServletResponseWrapper, и буферизовать вывод. Это сделано для того, чтобы вывод не поступал напрямую клиенту, но также позволяет защитить, если сервлет закроет поток, как указано в этом отрывке (выделено мной):
Статья
Из этой официальной статьи Sun можно сделать вывод, что закрытие
OutputStream
сервлета из сервлета - это нормальное явление, но не обязательное.источник
Общее их правило таково: если вы открыли поток, то вы должны его закрыть. Если нет, то и не надо. Убедитесь, что код симметричен.
В случае с
HttpServletResponse
, это немного менее однозначно, поскольку не очевидно, является ли вызовgetOutputStream()
операцией, открывающей поток. Javadoc просто говорит, что это "Returns a ServletOutputStream
"; аналогично дляgetWriter()
. В любом случае ясно, чтоHttpServletResponse
«владеет» потоком / писателем, и он (или контейнер) несет ответственность за его повторное закрытие.Итак, отвечая на ваш вопрос - нет, в этом случае вам не следует закрывать поток. Контейнер должен это делать, и если вы попадете туда раньше, вы рискуете внести в свое приложение небольшие ошибки.
источник
close()
когда я закончил с потоком, клиент немедленно возвращается, а остальная часть сервлета продолжает выполнение. Разве это не делает ответ более относительным? в отличие от окончательного да или нетЕсли есть вероятность, что фильтр может быть вызван для «включенного» ресурса, вам определенно не следует закрывать поток. Это приведет к сбою включаемого ресурса с исключением «поток закрыт».
источник
Вы должны закрыть поток, код чище, поскольку вы вызываете getOutputStream (), и поток не передается вам в качестве параметра, когда обычно вы просто используете его и не пытаетесь закрыть. В API сервлета не указано, что если выходной поток может быть закрыт или не должен быть закрыт, в этом случае вы можете безопасно закрыть поток, любой контейнер позаботится о закрытии потока, если он не был закрыт сервлетом.
Вот метод close () в Jetty, они закрывают поток, если он не закрыт.
public void close() throws IOException { if (_closed) return; if (!isIncluding() && !_generator.isCommitted()) commitResponse(HttpGenerator.LAST); else flushResponse(); super.close(); }
Также как разработчик фильтра вы не должны предполагать, что OutputStream не закрыт, вы всегда должны передавать другой OutputStream, если вы хотите изменить содержимое после того, как сервлет выполнил свою работу.
EDIT: я всегда закрываю поток, и у меня не было проблем с Tomcat / Jetty. Не думаю, что у вас должны возникнуть проблемы с каким-либо контейнером, старым или новым.
источник
Еще один аргумент против закрытия
OutputStream
. Посмотри на этот сервлет. Выдает исключение. Исключение отображается в файле web.xml на ошибку JSP:package ser; import java.io.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; @WebServlet(name = "Erroneous", urlPatterns = {"/Erroneous"}) public class Erroneous extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter out = resp.getWriter(); try { throw new IOException("An error"); } finally { // out.close(); } } }
Файл web.xml содержит:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <session-config> <session-timeout> 30 </session-timeout> </session-config> <error-page> <exception-type>java.io.IOException</exception-type> <location>/error.jsp</location> </error-page> </web-app>
И error.jsp:
<%@page contentType="text/html" pageEncoding="UTF-8" isErrorPage="true"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Error Page</title> </head> <body> <h1><%= exception.getMessage()%></h1> </body> </html>
При загрузке
/Erroneous
в браузере вы видите страницу с сообщением об ошибке «Ошибка». Но если вы не закомментируетеout.close()
строку в приведенном выше сервлете, повторно развернете приложение и перезагрузите,/Erroneous
вы ничего не увидите в браузере. Я понятия не имею, что происходит на самом деле, но полагаю, чтоout.close()
предотвращает обработку ошибок.Протестировано с Tomcat 7.0.50, Java EE 6 с использованием Netbeans 7.4.
источник