08 maja 2012

Asynchroniczne przetwarzanie w Servlet 3.0

Poniższy servlet kończy się wyjątkiem - java.lang.IllegalStateException - na linii 18, w której dostaję się do javax.servlet.AsyncContext. Dlaczego?

package pl.japila;

import java.io.IOException;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = "/AsyncServlet", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        AsyncContext asyncCtx = request.getAsyncContext();
        response.getWriter().printf("<h2>AsyncContext: %s</h2>", asyncCtx);
    }

}
Niech to będzie początkiem mojego eksperymentu naukowego, którego obiektem jesteś...Ty! :-)

10 komentarzy:

  1. Cytując JavaDoc: "getAsyncContext() Throws: IllegalStateException - if this request has not been put into asynchronous mode" - musisz najpierw zawołać startAsync().

    OdpowiedzUsuń
  2. Przed, po czy może w ramach metody?! Jakiej? Gdzie miałbym zawołać startAsync()?

    OdpowiedzUsuń
  3. Dokumentacja wydaje się jasna: najpierw musisz zawołać startAsync() w servlecie (która to metoda zwraca AsyncContext) a potem możesz wołać getAsyncContext() dowoli, niekoniecznie w servlecie, uzyskując ten sam obiekt typu AsyncContext. Zerknij na mój wpis o Servlet 3.0.

    OdpowiedzUsuń
  4. Jasna, jasna. Teraz przypominam sobie Twój wpis, ale jego zawartość trochę mnie przeraziła i nie pamiętam, czy dotarłem do samego końca.

    A dlaczego wołasz request.startAsync(request, response); w DownloadServletHandler.handleRequest?

    OdpowiedzUsuń
  5. Bo muszę :-). Specyfikacja wymaga, abym zawołał startAsync() wewnątrz servletu jeśli chcę obsłużyć żądanie asynchronicznie. W przeciwnym wypadku w chwili powrotu z doService() kontener zamknie połączenie i uzna je za obsłużone. Zobacz moje odpowiedzi na SO: [1] i [2].

    OdpowiedzUsuń
  6. Musisz startAsync(), ale nie(koniecznie) wariant z dwoma parametrami wejściowymi - startAsync(req, res). Pytam, dlaczego użyłeś wariantu dwuargumentowego? I tylko nie pisz mi, że "bo muszę", bo to za będzie za mało :-)

    OdpowiedzUsuń
  7. Prawdę mówiąc nie wiem - jeśli używasz oryginalnego obiektu żądania i odpowiedzi, wersja bezargumentowa wystarczy. Wersja dwuargumentowa ma zastosowanie jeśli chcesz dodatkowo opakować jeden lub oba obiekty - nie wiem, jakie ma to zastosowanie praktyczne w tym przypadku. Innymi słowy mój kod mógłby być nieco prostszy.

    OdpowiedzUsuń
  8. Gotcha! :-) Czułem, że do tego dojdziemy. Eksperyment się powiódł. Dziękuję za udział! Nagroda jest Twoja.

    OdpowiedzUsuń
  9. Powiem szczerze, że bardziej niż nagroda (uścisk dłoni odbiorę na Confiturze ;-)) interesuje mnie czego chciałeś dowieźć? Innymi słowy - czego spodziewałeś się po komentarzach czytelników?

    OdpowiedzUsuń
  10. Niczego nie dowodziłem, a jedynie uczyłem się w doborowym towarzystwie :) Coś mi mówi, że krótkie wpisy mogą być większą inspiracją do rozmów/wymiany doświadczeń niż dłuższe, a i prościej się je pisze. Ostatecznie chciałbym poświęcić więcej czasu na nagrania/skrinkasty. Właśnie przygotowuję scenariusz.

    OdpowiedzUsuń