Como os servlets funcionam? Instanciação, sessões, variables ​​compartilhadas e multithreading

Suponha que eu tenha um servidor que contém vários servlets. Para informações transmitidas entre esses servlets, estou configurando variables ​​de session e instância.

Agora, se dois ou mais usuários enviarem solicitação para esse servidor, o que acontece com as variables ​​da session? Serão todos comuns para todos os usuários ou serão diferentes para cada usuário? Se eles são diferentes, como o servidor foi capaz de diferenciar usuários diferentes?

Mais uma pergunta semelhante, se houver n usuários acessando um determinado servlet, esse servlet será instanciado apenas na primeira vez em que o primeiro usuário o accessu ou será instanciado para todos os usuários separadamente? Em outras palavras, o que acontece com as variables ​​de instância?

ServletContext

Quando o contêiner do servlet (como o Apache Tomcat ) é inicializado, ele implementará e carregará todos os seus aplicativos da web. Quando um aplicativo da Web é carregado, o contêiner do servlet cria o ServletContext uma vez e o mantém na memory do servidor. O arquivo web.xml do aplicativo da web é analisado e cada , e encontrado (ou cada class anotada com @WebServlet , @WebFilter e @WebListener respectivamente) é instanciado uma vez e mantido na memory do servidor como bem. Para cada filtro instanciado, seu método init() é invocado com um novo FilterConfig .

Quando o contêiner do servlet é desligado, ele descarrega todos os aplicativos da Web, chama o método destroy() de todos os servlets e filtros inicializados e todas as ocorrências de ServletContext , Servlet , Filter e Listener são descartadas.

Quando um Servlet tem um valor ou @WebServlet(loadOnStartup) maior que 0 , seu método init() também é chamado durante a boot com um novo ServletConfig . Esses servlets são inicializados na mesma ordem especificada por esse valor (1 -> 1st, 2 -> 2nd, etc). Se o mesmo valor for especificado para mais de um servlet, cada um desses servlets será carregado na ordem em que aparecem no @WebServlet class web.xml ou @WebServlet . Caso o valor “load-on-startup” esteja ausente, o método init() será invocado sempre que a solicitação HTTP atingir esse servlet pela primeira vez.

HttpServletRequest e HttpServletResponse

O contêiner do servlet é conectado a um servidor da Web que atende a solicitações HTTP em um determinado número de porta (a porta 8080 é geralmente usada durante o desenvolvimento e a porta 80 em produção). Quando um cliente (usuário com um navegador da Web) envia uma solicitação HTTP, o contêiner de servlet cria novos objects HttpServletResponse e HttpServletResponse e os transmite por meio de qualquer cadeia de Filter definida e, eventualmente, a instância do Servlet .

No caso de filtros , o método doFilter() é invocado. Quando seu código chama chain.doFilter(request, response) , a solicitação e a resposta continuam no próximo filtro ou atingem o servlet se não houver filtros restantes.

No caso de servlets , o método service() é chamado. Por padrão, esse método determina qual dos methods doXxx() a invocar baseado fora de request.getMethod() . Se o método determinado estiver ausente do servlet, um erro HTTP 405 será retornado na resposta.

O object request fornece access a todas as informações sobre a solicitação HTTP, como seus headers e corpo. O object de resposta fornece a capacidade de controlar e enviar a resposta HTTP da maneira desejada, por exemplo, permitindo que você defina os headers e o corpo (geralmente com conteúdo HTML gerado a partir de um arquivo JSP). Quando a resposta HTTP é confirmada e concluída, os objects de solicitação e resposta são reciclados e feitos para reutilização.

HttpSession

Quando um cliente visita o webapp pela primeira vez e / ou o HttpSession é obtido pela primeira vez via request.getSession() , o contêiner do servlet cria um novo object HttpSession , gera um ID longo e único (que você pode obter por session.getId() ) e armazene-o na memory do servidor. O contêiner do servlet também define um Cookie no header Set-Cookie da resposta HTTP com JSESSIONID como seu nome e o ID da session exclusiva como seu valor.

De acordo com a especificação do cookie HTTP (um contrato que um navegador web decente e um servidor web têm de aderir), o cliente (o navegador da web) é obrigado a enviar esse cookie de volta em solicitações subsequentes no header Cookie enquanto o cookie for válido (ou seja, o ID exclusivo deve se referir a uma session não expirada e o domínio e o caminho estão corretos). Usando o monitor de tráfego HTTP embutido do seu navegador, você pode verificar se o cookie é válido (pressione F12 no Chrome / Firefox 23+ / IE9 + e verifique a guia Rede / Rede ). O contêiner do servlet verificará o header Cookie de cada solicitação HTTP recebida quanto à presença do cookie com o nome JSESSIONID e usará seu valor (o ID da session) para obter o HttpSession associado da memory do servidor.

O HttpSession permanece ativo até que não tenha sido usado por mais do que o valor de tempo limite especificado em , uma configuração no web.xml . O valor do tempo limite é padronizado para 30 minutos. Portanto, quando o cliente não visita o aplicativo da web por mais tempo do que o especificado, o contêiner do servlet recolhe a session. Toda solicitação subseqüente, mesmo com o cookie especificado, não terá mais access à mesma session; o contêiner do servlet criará uma nova session.

No lado do cliente, o cookie de session permanece ativo enquanto a instância do navegador estiver em execução. Portanto, se o cliente fechar a instância do navegador (todas as guias / janelas), a session será descartada no lado do cliente. Em uma nova instância do navegador, o cookie associado à session não existiria e, portanto, não seria mais enviado. Isso faz com que uma session de HTTPSession inteiramente nova seja criada, com um cookie de session inteiramente novo sendo usado.

Em poucas palavras

  • O ServletContext vive enquanto o aplicativo da web vive. É compartilhado entre todas as solicitações em todas as sessões.
  • O HttpSession vive enquanto o cliente estiver interagindo com o aplicativo da Web com a mesma instância do navegador e a session não expirou no servidor. É compartilhado entre todas as solicitações na mesma session.
  • O HttpServletRequest e o HttpServletResponse residem no momento em que o servlet recebe uma solicitação HTTP do cliente, até que a resposta completa (a página da web) tenha chegado. Não é compartilhado em outro lugar.
  • Todas as instâncias de Servlet , Filter e Listener estão ativas enquanto o aplicativo da web estiver ativo. Eles são compartilhados entre todas as solicitações em todas as sessões.
  • Qualquer attribute definido em ServletContext , HttpServletRequest e HttpSession HttpServletRequest HttpSession enquanto o object em questão existir. O object em si representa o “escopo” em estruturas de gerenciamento de beans, como JSF, CDI, Spring, etc. Essas estruturas armazenam seus beans com escopo definido como um attribute de seu escopo correspondente mais próximo.

Segurança de Roscas

Dito isto, a sua maior preocupação é possivelmente a segurança dos fios . Agora você deve saber que os servlets e filtros são compartilhados entre todas as solicitações. Essa é a coisa legal do Java, ele é multissegmentado e threads diferentes (leia-se: solicitações HTTP) podem fazer uso da mesma instância. Caso contrário, seria muito caro recriar, init() e destroy() para cada solicitação.

Você também deve perceber que nunca deve atribuir dados de escopo de solicitação ou session como uma variável de instância de um servlet ou filtro. Ele será compartilhado entre todas as outras solicitações em outras sessões. Isso não é thread-safe! O exemplo abaixo ilustra isso:

 public class ExampleServlet extends HttpServlet { private Object thisIsNOTThreadSafe; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Object thisIsThreadSafe; thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests! thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe. } } 

Veja também:

  • Qual é a diferença entre JSF, Servlet e JSP?
  • Melhor opção para gerenciamento de session em Java
  • Diferença entre / e / * no padrão de URL de mapeamento de servlet
  • doGet e doPost em Servlets
  • O servlet parece lidar com várias solicitações simultâneas de navegador de forma síncrona
  • Por que os Servlets não são seguros para threads?

Sessões

insira a descrição da imagem aquiinsira a descrição da imagem aqui

Resumindo: o servidor web emite um identificador único para cada visitante em sua primeira visita. O visitante deve trazer de volta esse documento para que ele seja reconhecido na próxima vez. Esse identificador também permite que o servidor segregar corretamente objects pertencentes a uma session em relação a outra.

Instanciação de servlet

Se o carregamento no arranque for falso :

insira a descrição da imagem aquiinsira a descrição da imagem aqui

Se o carregamento na boot for verdadeiro :

insira a descrição da imagem aquiinsira a descrição da imagem aqui

Quando estiver no modo de serviço e na ranhura, o mesmo servlet funcionará nas solicitações de todos os outros clientes.

insira a descrição da imagem aqui

Por que não é uma boa ideia ter uma instância por cliente? Pense sobre isso: você vai contratar um cara de pizza para cada pedido que veio? Faça isso e você estará fora do negócio em nenhum momento.

Ele vem com um pequeno risco embora. Lembre-se: esse cara solteiro possui todas as informações do pedido em seu bolso: portanto, se você não for cauteloso sobre segurança de thread em servlets , ele pode acabar dando a ordem errada a um determinado cliente.

A session nos servlets Java é igual à session em outras linguagens, como o PHP. É exclusivo para o usuário. O servidor pode rastreá-lo de maneiras diferentes, como cookies, reescrita de url, etc. Este artigo doc Java explica isso no contexto de servlets Java e indica que exatamente como a session é mantida é um detalhe de implementação deixado para os projetistas do servidor. A especificação apenas estipula que ela deve ser mantida como exclusiva para um usuário em várias conexões com o servidor. Confira este artigo da Oracle para mais informações sobre as duas perguntas.

Edit Há um excelente tutorial aqui sobre como trabalhar com a session dentro de servlets. E aqui está um capítulo da Sun sobre Java Servlets, o que eles são e como usá-los. Entre esses dois artigos, você deve poder responder a todas as suas perguntas.

Quando o servletcontainer (como o Apache Tomcat) for inicializado, ele será lido no arquivo web.xml (somente um por aplicativo) se alguma coisa der errado ou aparecer erro no console do contêiner, caso contrário, ele implementará e carregará todos os webapplications usando web .xml (assim chamado como descritor de implantação).

Durante a fase de instanciação do servlet, servletInstance está pronto, mas não pode atender à solicitação do cliente porque está faltando duas informações:
1: informação contextual
2: informações iniciais de configuração

O mecanismo de servlet cria o object de interface servletConfig encapsulando as informações ausentes acima no mecanismo de servlet chama init () do servlet, fornecendo as referências de object servletConfig como argumento. Uma vez que o init () esteja completado, o servlet está pronto para executar o pedido do cliente.

Q) No tempo de vida do servlet quantas instanciações e initaializações acontecem ??

A) apenas uma vez (para cada solicitação do cliente um novo thread é criado) apenas uma instância do servlet serve qualquer número do pedido do cliente, ou seja, depois de servir um servidor de pedidos do cliente não morre. Ele aguarda por outras solicitações do cliente, ou seja, qual CGI (para cada solicitação do cliente, um novo processo é criado), a limitação é superada com o servlet (o mecanismo de servlet internamente cria o encadeamento).

Q) Como funciona o conceito de session?

A) sempre que getSession () é chamado no object HttpServletRequest

Etapa 1 : o object de solicitação é avaliado para ID de session recebida.

Etapa 2 : se a ID não disponível, um novo object HttpSession for criado e seu ID de session correspondente for gerado (por exemplo, HashTable), o ID da session será armazenado no object de resposta httpservlet e a referência do object HttpSession será retornada ao servlet (doGet / doPost).

Etapa 3 : se ID disponível novo object de session não for criado, o ID de session será selecionado a partir da pesquisa de object de solicitação na coleção de sessões usando a ID de session como a chave.

Depois que a pesquisa for bem-sucedida, o ID de session será armazenado em HttpServletResponse e as referências de object de session exsisting serão retornadas para o doGet () ou doPost () do UserDefineservlet.

Nota:

1) quando o controle sai do código do servlet para o cliente, não se esqueça que o object da session está sendo mantido pelo servletcontainer, por exemplo, servletengine

2) multithreading é deixado para servlet pessoas devlopers para implementar ou seja, lidar com o pedido múltiplo do cliente nada se preocupar com código multithread

Forma Inshort:

Um servlet é criado quando o aplicativo é iniciado (implementado no contêiner do servlet) ou quando é acessado pela primeira vez (dependendo da configuração de carregamento na boot) quando o servlet é instanciado, o método init () do servlet é chamado em seguida, o servlet (sua única instância) manipula todas as solicitações (seu método service () é chamado por vários encadeamentos). É por isso que não é aconselhável ter qualquer synchronization nele, e você deve evitar variables ​​de instância do servlet quando o aplicativo é removido (o contêiner do servlet para), o método destroy () é chamado.

Sessões – o que Chris Thompson disse.

Instanciação – um servlet é instanciado quando o contêiner recebe a primeira solicitação mapeada para o servlet (a menos que o servlet esteja configurado para carregar na boot com o elemento no web.xml ). A mesma instância é usada para atender a solicitações subsequentes.

A Especificação de Servlet JSR-315 define claramente o comportamento do contêiner de web nos methods de serviço (e doGet, doPost, doPut etc.) (2.3.3.1 Problemas de multithread, Página 9):

Um contêiner de servlet pode enviar solicitações simultâneas por meio do método de serviço do servlet. Para lidar com as solicitações, o desenvolvedor de servlet deve fazer provisões adequadas para o processamento simultâneo com vários encadeamentos no método de serviço.

Embora não seja recomendado, uma alternativa para o desenvolvedor é implementar a interface SingleThreadModel que requer o contêiner para garantir que haja apenas um thread de solicitação de cada vez no método de serviço. Um contêiner de servlet pode satisfazer esse requisito, serializando solicitações em um servlet ou mantendo um conjunto de instâncias de servlet. Se o servlet fizer parte de um aplicativo da Web que tenha sido marcado como distribuível, o contêiner poderá manter um conjunto de instâncias de servlet em cada JVM com a qual o aplicativo é distribuído.

Para servlets que não implementam a interface SingleThreadModel, se o método de serviço (ou methods como doGet ou doPost que são despachados para o método de serviço da class abstrata HttpServlet) tiver sido definido com a palavra-chave sincronizada, o contêiner do servlet não poderá usar a abordagem do conjunto de instâncias , mas deve serializar solicitações por meio dele. É altamente recomendável que os Desenvolvedores não sincronizem o método de serviço (ou methods enviados a ele) nessas circunstâncias, devido aos efeitos prejudiciais no desempenho

Não. Os servlets não são seguros para roscas

O é permite acessar mais de um encadeamento de cada vez

se vc quiser fazer isso Servlet como Thread safe., U pode ir para

Implement SingleThreadInterface(i) que é uma interface em branco não existe

methods

ou podemos ir para os methods de synchronization

podemos fazer todo o método de serviço como sincronizado usando sincronizado

keword na frente do método

Exemplo::

 public Synchronized class service(ServletRequest request,ServletResponse response)throws ServletException,IOException 

ou podemos colocar o bloco do código no bloco sincronizado

Exemplo::

 Synchronized(Object) { ----Instructions----- } 

Eu sinto que o bloco sincronizado é melhor do que fazer todo o método

Sincronizado