java multithreading servlets session-variables instance-variables

java - ¿Cómo funcionan los servlets? Instanciación, sesiones, variables compartidas y multihilo.



multithreading session-variables (7)

Supongamos que tengo un servidor web que contiene numerosos servlets. Para la información que pasa entre esos servlets, estoy configurando las variables de sesión y de instancia.

Ahora, si 2 o más usuarios envían solicitudes a este servidor, ¿qué sucede con las variables de sesión? ¿Serán todos comunes para todos los usuarios o serán diferentes para cada usuario? Si son diferentes, ¿cómo pudo el servidor diferenciar entre diferentes usuarios?

Una pregunta más similar, si hay n usuarios que acceden a un servlet en particular, entonces este servlet se crea una instancia solo la primera vez que el primer usuario accede o se crea una instancia para todos los usuarios por separado. En otras palabras, ¿qué pasa con las variables de instancia?


ServletContext

Cuando el contenedor de servlets (como Apache Tomcat ) se inicie, implementará y cargará todas sus aplicaciones web. Cuando se carga una aplicación web, el contenedor de servlets crea el ServletContext una vez y lo guarda en la memoria del servidor. El archivo web.xml la aplicación web se analiza, y cada <servlet> , <filter> y <listener> encontrado (o cada clase anotada con @WebServlet , @WebFilter y @WebListener respectivamente) se @WebListener una instancia y se guarda en la memoria del servidor como bien. Para cada filtro instanciado, su método init() se invoca con un nuevo FilterConfig .

Cuando el contenedor de servlets se apaga, descarga todas las aplicaciones web, invoca el método destroy() de todos sus servlets y filtros inicializados, y todas las instancias de ServletContext , Servlet , Filter y Listener se eliminan.

Cuando un Servlet tiene un valor de <servlet><load-on-startup> o @WebServlet(loadOnStartup) mayor que 0 , su método init() también se invoca durante el inicio con un nuevo ServletConfig . Esos servlets se inicializan en el mismo orden especificado por ese valor (1 -> 1st, 2 -> 2nd, etc.). Si se especifica el mismo valor para más de un servlet, entonces cada uno de esos servlets se carga en el orden en que aparecen en web.xml , o @WebServlet classloading. En el caso de que el valor de "carga en el inicio" esté ausente, el método init() se invocará cada vez que la solicitud HTTP llegue a ese servlet por primera vez.

HttpServletRequest y HttpServletResponse

El contenedor de servlets se adjunta a un servidor web que escucha las solicitudes HTTP en un número de puerto determinado (el puerto 8080 se usa generalmente durante el desarrollo y el puerto 80 en producción). Cuando un cliente (usuario con un navegador web) envía una solicitud HTTP, el contenedor de servlets crea nuevos objetos HttpServletRequest y HttpServletResponse y los pasa a través de cualquier cadena de Filter definida y, eventualmente, la instancia de Servlet .

En el caso de los filters , se invoca el método doFilter() . Cuando su código llama chain.doFilter(request, response) , la solicitud y la respuesta continúan en el siguiente filtro, o golpean el servlet si no hay filtros restantes.

En el caso de servlets , se invoca el método service() . De forma predeterminada, este método determina cuál de los métodos doXxx() invoca basándose en request.getMethod() . Si el método determinado está ausente del servlet, se devuelve un error HTTP 405 en la respuesta.

El objeto de solicitud proporciona acceso a toda la información sobre la solicitud HTTP, como sus encabezados y cuerpo. El objeto de respuesta ofrece la capacidad de controlar y enviar la respuesta HTTP de la forma que desee, por ejemplo, permitiéndole establecer los encabezados y el cuerpo (generalmente con contenido HTML generado desde un archivo JSP). Cuando la respuesta HTTP se confirma y finaliza, tanto los objetos de solicitud como los de respuesta se reciclan y se hacen para su reutilización.

Sesión

Cuando un cliente visita la aplicación web por primera vez y / o se obtiene HttpSession por primera vez a través de request.getSession() , el contenedor de servlets crea un nuevo objeto HttpSession , genera un ID largo y único (que puede obtener por session.getId() ), y guárdelo en la memoria del servidor. El contenedor de servlets también establece una Cookie en el encabezado Set-Cookie de la respuesta HTTP con JSESSIONID como su nombre y el ID de sesión único como su valor.

Según la especificación de la cookie HTTP (un contrato que un navegador web y un servidor web decentes deben cumplir), se requiere que el cliente (el navegador web) envíe esta cookie en solicitudes posteriores en el encabezado de la cookie, siempre que la cookie sea válido (es decir, la ID única debe referirse a una sesión no caducada y el dominio y la ruta son correctos). Con el monitor de tráfico HTTP incorporado de su navegador, puede verificar que la cookie sea válida (presione F12 en Chrome / Firefox 23+ / IE9 + y verifique la pestaña Red / Red ). El contenedor de servlets comprobará el encabezado de la Cookie de cada solicitud HTTP entrante para detectar la presencia de la cookie con el nombre JSESSIONID y usará su valor (el ID de sesión) para obtener la HttpSession asociada de la memoria del servidor.

La HttpSession permanece activa hasta que no se ha utilizado por más del valor de tiempo de espera especificado en <session-timeout> , una configuración en web.xml . El valor de tiempo de espera predeterminado es de 30 minutos. Entonces, cuando el cliente no visita la aplicación web por más tiempo del tiempo especificado, el contenedor de servlet desecha la sesión. Cada solicitud posterior, incluso con la cookie especificada, ya no tendrá acceso a la misma sesión; El contenedor servlet creará una nueva sesión.

En el lado del cliente, la cookie de sesión permanece activa mientras se ejecute la instancia del navegador. Entonces, si el cliente cierra la instancia del navegador (todas las pestañas / ventanas), entonces la sesión se corta en el lado del cliente. En una nueva instancia del navegador, la cookie asociada con la sesión no existiría, por lo que ya no se enviaría. Esto hace que se cree una sesión HTTPSession completamente nueva, con un inicio de uso de una cookie de sesión completamente nueva.

En una palabra

  • El ServletContext vive durante el tiempo que la aplicación web. Se comparte entre todas las solicitudes en todas las sesiones.
  • La HttpSession mientras el cliente interactúe con la aplicación web con la misma instancia del navegador y la sesión no se haya agotado en el servidor. Se comparte entre todas las solicitudes en la misma sesión.
  • HttpServletRequest y HttpServletResponse vivo desde el momento en que el servlet recibe una solicitud HTTP del cliente, hasta que llega la respuesta completa (la página web). No se comparte en otro lugar.
  • Todas las instancias de Servlet , Filter y Listener vivo mientras la aplicación web esté activa. Se comparten entre todas las solicitudes en todas las sesiones.
  • Cualquier attribute que esté definido en ServletContext , HttpServletRequest y HttpSession vivirá mientras viva el objeto en cuestión. El objeto en sí mismo representa el "alcance" en los marcos de administración de beans, como JSF, CDI, Spring, etc. Esos marcos almacenan sus beans con alcance como un attribute de su alcance más cercano.

Seguridad del hilo

Dicho esto, su principal preocupación es posiblemente la seguridad de los hilos . Ahora debe saber que los servlets y los filtros se comparten entre todas las solicitudes. Eso es lo bueno de Java, es multiproceso y diferentes hilos (leídos: solicitudes HTTP) pueden hacer uso de la misma instancia. De lo contrario, sería demasiado costoso recrearlos, init() y destroy() para cada solicitud.

También debe darse cuenta de que nunca debe asignar ninguna solicitud o datos de ámbito de sesión como una variable de instancia de un servlet o filtro. Se compartirá entre todas las demás solicitudes en otras sesiones. ¡Eso no es seguro para los hilos! El siguiente ejemplo ilustra esto:

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. } }

Ver también:


Sesiones

En resumen: el servidor web emite un identificador único para cada visitante en su primera visita. El visitante debe traer esa identificación para que sea reconocido la próxima vez. Este identificador también permite al servidor segregar adecuadamente los objetos que pertenecen a una sesión y los de otra.

Creación de Servlets

Si load-on-startup es falso :

Si load-on-startup es verdadero :

Una vez que esté en el modo de servicio y en la ranura, el mismo servlet funcionará en las solicitudes de todos los demás clientes.

¿Por qué no es una buena idea tener una instancia por cliente? Piense en esto: ¿Contratará a un tipo de pizza por cada pedido que llegue? Haz eso y estarás fuera del negocio en poco tiempo.

Aunque viene con un pequeño riesgo. Recuerde: este hombre soltero guarda toda la información del pedido en su bolsillo: por lo tanto, si no es cauteloso acerca de la seguridad de los hilos en los servlets , puede terminar dando el orden incorrecto a un determinado cliente.


Cuando se inicie el contenedor de servlets (como Apache Tomcat), se leerá del archivo web.xml (solo uno por aplicación) si algo sale mal o muestra un error en la consola del lado del contenedor; de lo contrario, se implementará y cargará toda la web. aplicaciones mediante el uso de web.xml (llamado así como descriptor de implementación).

Durante la fase de creación de instancias del servlet, la instancia del servlet está lista pero no puede atender la solicitud del cliente porque falta con dos datos:
1: información de contexto
2: información de configuración inicial

El motor de Servlet crea un objeto de interfaz servletConfig que encapsula la información que falta arriba en él. El motor de servlet llama a init () del servlet al proporcionar referencias de objeto servletConfig como un argumento. Una vez que init () se ejecute por completo, el servlet estará listo para atender la solicitud del cliente.

P) En la vida útil del servlet, ¿cuántas veces ocurre la creación de instancias y la inicialización?

A) solo una vez (para cada solicitud de cliente se crea un nuevo subproceso) solo una instancia del servlet sirve cualquier número de la solicitud del cliente, es decir, después de atender a un servidor de solicitud del cliente no muere. Espera otras solicitudes del cliente, es decir, qué limitación CGI (para cada solicitud de cliente se crea un nuevo proceso) se supera con el servlet (el motor de servlet interno crea el subproceso).

P) ¿Cómo funciona el concepto de sesión?

A) cada vez que se llama a getSession () en el objeto HttpServletRequest

Paso 1 : el objeto de solicitud se evalúa para el ID de sesión entrante.

Paso 2 : si el ID no está disponible, se crea un nuevo objeto HttpSession y se genera su correspondiente ID de sesión (es decir, de HashTable) El ID de sesión se almacena en el objeto de respuesta httpservlet y la referencia del objeto HttpSession se devuelve al servlet (doGet / doPost) .

Paso 3 : si no se crea el nuevo objeto de sesión ID disponible, el ID de sesión se extrae de la solicitud. La búsqueda de objetos se realiza en la recopilación de sesiones utilizando el ID de sesión como clave.

Una vez que la búsqueda es exitosa, el ID de sesión se almacena en HttpServletResponse y las referencias de objetos de sesión existentes se devuelven al doGet () o doPost () de UserDefineservlet.

Nota:

1) cuando el control sale del código de servlet al cliente, no olvide que el contenedor de servlet retiene el objeto de sesión, es decir, el motor de servlet

2) los subprocesos múltiples se dejan a los desarrolladores de servlets para que los implementen, es decir, no manejan las múltiples solicitudes del cliente para preocuparse por el código de subprocesos múltiples

En forma corta:

Se crea un servlet cuando se inicia la aplicación (se implementa en el contenedor del servlet) o cuando se accede por primera vez (según la configuración de carga al inicio) cuando se crea una instancia del servlet, se llama al método init () del servlet entonces el servlet (su única instancia) maneja todas las solicitudes (su método service () está siendo llamado por múltiples hilos). Es por eso que no es recomendable tener sincronización, y debe evitar las variables de instancia del servlet cuando la aplicación no está desplegada (el contenedor del servlet se detiene), se llama al método destroy ().


La especificación de Servlet JSR-315 define claramente el comportamiento del contenedor web en los métodos del servicio (y doGet, doPost, doPut, etc.) (2.3.3.1 Problemas de subprocesamiento múltiple, página 9):

Un contenedor de servlets puede enviar solicitudes simultáneas a través del método de servicio del servlet. Para manejar las solicitudes, el desarrollador de Servlet debe hacer las provisiones adecuadas para el procesamiento simultáneo con múltiples hilos en el método de servicio.

Aunque no se recomienda, una alternativa para el desarrollador es implementar la interfaz SingleThreadModel que requiere que el contenedor garantice que solo hay un subproceso de solicitud a la vez en el método de servicio. Un contenedor de servlets puede satisfacer este requisito al serializar las solicitudes en un servlet, o al mantener un conjunto de instancias de servlet. Si el servlet es parte de una aplicación web que ha sido marcada como distribuible, el contenedor puede mantener un grupo de instancias de servlet en cada JVM en la que se distribuye la aplicación.

Para los servlets que no implementan la interfaz SingleThreadModel, si el método de servicio (o métodos como doGet o doPost que se distribuyen al método de servicio de la clase abstracta HttpServlet) se ha definido con la palabra clave sincronizada, el contenedor del servlet no puede usar el enfoque del grupo de instancias , pero debe serializar las solicitudes a través de él. Se recomienda encarecidamente que los Desarrolladores no sincronicen el método de servicio (o los métodos que se le envíen) en estas circunstancias debido a los efectos perjudiciales sobre el rendimiento


La sesión en servlets de Java es la misma que la sesión en otros idiomas, como PHP. Es exclusivo del usuario. El servidor puede realizar un seguimiento de él de diferentes maneras, como las cookies, la reescritura de URL, etc. Este artículo de documentación de Java lo explica en el contexto de los servlets de Java e indica que exactamente cómo se mantiene la sesión es un detalle de implementación que se deja a los diseñadores del servidor. La especificación solo estipula que debe mantenerse como único para un usuario en múltiples conexiones al servidor. Consulte este artículo de Oracle para obtener más información sobre sus dos preguntas.

Editar Aquí hay un excelente tutorial sobre cómo trabajar con sesiones dentro de servlets. Y here hay un capítulo de Sun sobre los Servlets de Java, qué son y cómo usarlos. Entre esos dos artículos, debería poder responder a todas sus preguntas.


No. Los servlets no son seguros para hilos.

El es permite acceder a más de un hilo a la vez

Si quieres que sea Servlet como seguro para subprocesos, puedes ir por

Implement SingleThreadInterface(i) que es una interfaz en blanco que no hay

metodos

O podemos ir por los métodos de sincronización.

Podemos hacer todo el método de servicio como sincronizado utilizando sincronizado

Keword delante del método

Ejemplo::

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

O podemos poner el bloque puesto del código en el bloque sincronizado.

Ejemplo::

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

Siento que el bloque sincronizado es mejor que hacer todo el método.

Sincronizado


Sesiones - lo que dijo Chris Thompson.

Creación de instancias : un servlet se crea una instancia cuando el contenedor recibe la primera solicitud asignada al servlet (a menos que el servlet esté configurado para cargarse en el inicio con el elemento <load-on-startup> en web.xml ). La misma instancia se utiliza para servir solicitudes posteriores.