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

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é ocurre 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 accediendo a un servlet en particular, este servlet solo se instanciará la primera vez que el primer usuario accedió o se creará una instancia para todos los usuarios por separado. En otras palabras, ¿qué ocurre con las variables de instancia?

    ServletContext

    Cuando el contenedor de servlets (como Apache Tomcat ) se inicie, desplegará y cargará todas sus aplicaciones web. Cuando se carga una aplicación web, el contenedor de servlets crea el ServletContext una vez y lo mantiene en la memoria del servidor. El archivo web.xml la aplicación web se analiza y cada , y encontrados (o cada clase anotada con @WebServlet , @WebFilter y @WebListener respectivamente) se instancia una vez 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 descartan.

    Cuando un Servlet tiene un valor 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 -> 1 °, 2 -> 2 °, etc.). Si se especifica el mismo valor para más de un servlet, cada uno de esos servlets se carga en el orden en que aparecen en la @WebServlet clases web.xml o @WebServlet . En el caso de que el valor de “carga al inicio” esté ausente, se invocará el método init() cada vez que la solicitud HTTP golpee ese servlet por primera vez.

    HttpServletRequest y HttpServletResponse

    El contenedor del servlet está conectado a un servidor web que escucha las solicitudes HTTP en un determinado número de puerto (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 servlet crea nuevos objetos HttpServletRequest y HttpServletResponse y los pasa a través de cualquier cadena de Filter definida y, finalmente, la instancia de Servlet .

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

    En el caso de los servlets , se invoca el método service() . De forma predeterminada, este método determina cuál de los métodos doXxx() invocar basado 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 proporciona la capacidad de controlar y enviar la respuesta HTTP de la manera que desee, por ejemplo, lo que le permite configurar los encabezados y el cuerpo (generalmente con contenido HTML generado a partir de un archivo JSP). Cuando la respuesta HTTP se confirma y finaliza, tanto los objetos de solicitud como de respuesta se reciclan y se vuelven a utilizar.

    HttpSession

    Cuando un cliente visita la aplicación web por primera vez y / o la HttpSession se obtiene por primera vez a través de request.getSession() , el contenedor servlet crea un nuevo objeto HttpSession , genera una identificación larga y única (que puede obtener por session.getId() ), y lo almacena 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 la ID de sesión única como su valor.

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

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

    En el lado del cliente, la cookie de sesión permanece activa mientras se ejecuta la instancia del navegador. Por lo tanto, si el cliente cierra la instancia del navegador (todas las tabs / ventanas), la sesión se descarta por el lado del cliente. En una nueva instancia del navegador, la cookie asociada a la sesión no existiría, por lo que ya no se enviaría. Esto hace que se cree una sesión de HTTPSession completamente nueva, con una cookie de sesión completamente nueva que se usa.

    En una palabra

    • ServletContext vive mientras viva la aplicación web. Se comparte entre todas las solicitudes en todas las sesiones.
    • La HttpSession vive mientras el cliente esté interactuando con la aplicación web con la misma instancia del navegador, y la sesión no ha excedido el tiempo de espera en el servidor. Se comparte entre todas las solicitudes en la misma sesión.
    • HttpServletRequest y HttpServletResponse 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 viven mientras dure la aplicación web. Se comparten entre todas las solicitudes en todas las sesiones.
    • Cualquier attribute que esté definido en ServletContext , HttpServletRequest y HttpSession vivirá mientras el objeto en cuestión viva. El objeto en sí mismo representa el “scope” en los marcos de gestión de beans como JSF, CDI, Spring, etc. Esos marcos almacenan sus beans con ámbito como un attribute de su ámbito de coincidencia más cercano.

    Seguridad de subprocesos

    Dicho esto, su mayor 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 (leer: solicitudes HTTP) pueden hacer uso de la misma instancia. De lo contrario, sería demasiado caro recrear, init() y destroy() para cada solicitud.

    También debe tener en cuenta 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 subprocesos! 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:

    • ¿Cuál es la diferencia entre JSF, Servlet y JSP?
    • La mejor opción para la gestión de sesiones en Java
    • Diferencia entre / y / * en el patrón de url de mapeo de servlets
    • doGet y doPost en Servlets
    • Servlet parece manejar múltiples solicitudes concurrentes de navegador sincrónicamente
    • ¿Por qué los servlets no son seguros?

    Sesiones

    enter image description hereenter image description here

    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 que el servidor segregue adecuadamente los objetos propiedad de una sesión frente a la de otra.

    Instanciación de servlet

    Si load-on-startup es falso :

    enter image description hereenter image description here

    Si load-on-startup es verdadero :

    enter image description hereenter image description here

    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.

    enter image description here

    ¿Por qué no es una buena idea tener una instancia por cliente? Piense en esto: ¿Contratará a un tipo de pizza por cada orden que venga? Hazlo y estarías fuera del negocio en muy poco tiempo.

    Sin embargo, 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 tiene cuidado con la seguridad del hilo en los servlets , es posible que termine dando el orden incorrecto a un determinado cliente.

    La sesión en los servlets de Java es la misma que en otros lenguajes, como PHP. Es único para el usuario. El servidor puede realizar un seguimiento de la misma de diferentes maneras, como cookies, 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 dejado a los diseñadores del servidor. La especificación solo estipula que debe mantenerse como único para un usuario a través de 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 la sesión dentro de los servlets. Y aquí hay un capítulo de Sun sobre Java Servlets, qué son y cómo usarlos. Entre esos dos artículos, debería ser capaz de responder todas sus preguntas.

    Cuando el servletcontainer (como Apache Tomcat) se inicia, se leerá desde el archivo web.xml (solo uno por aplicación) si algo sale mal o aparece un error en la consola lateral del contenedor; de lo contrario, se implementará y cargará todas las aplicaciones web mediante web. .xml (llamado así como descriptor de despliegue).

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

    El motor Servlet crea un objeto de interfaz servletConfig que encapsula la información que falta más arriba en el motor de servlets llama a init () de servlet al proporcionar referencias de objetos servletConfig como argumento. Una vez que init () se ha ejecutado, el servlet está listo para server la solicitud del cliente.

    P) En el tiempo de vida de servlet, ¿cuántas veces ocurre la instanciación y la incialización?

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

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

    A) siempre que se llame a getSession () en el objeto HttpServletRequest

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

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

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

    Una vez que la búsqueda tiene éxito, la ID de sesión se almacena en HttpServletResponse y las referencias de objetos de sesión existentes se devuelven a doGet () o doPost () de UserDefineservlet.

    Nota:

    1) cuando el control se va del código de servlet al cliente, no olvide que el objeto de sesión está siendo retenido por servletcontainer, es decir, servletengine

    2) el subprocesamiento múltiple se deja a las personas de servlets devlopers para implementar, es decir, manejar la solicitud múltiple del cliente, nada que preocuparse por el código multithread

    Forma incompleta:

    Se crea un servlet cuando la aplicación se inicia (se implementa en el contenedor de servlets) 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 () es llamado por múltiples hilos). Es por eso que no es recomendable tener ninguna sincronización en él, y debe evitar las variables de instancia del servlet cuando la aplicación no se despliegue (el contenedor de servlets se detiene), se llama al método destroy ().

    Sesiones : lo que dijo Chris Thompson.

    Instanciación : se crea una instancia de un servlet cuando el contenedor recibe la primera solicitud asignada al servlet (a menos que el servlet esté configurado para cargar al inicio con el elemento en web.xml ). La misma instancia se usa para atender solicitudes posteriores.

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

    Un contenedor de servlet puede enviar solicitudes simultáneas a través del método de servicio del servlet. Para manejar las solicitudes, el Desarrollador de Servlets debe hacer provisiones adecuadas para el procesamiento concurrente 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 hilo de solicitud a la vez en el método de servicio. Un contenedor de servlet puede cumplir este requisito serializando solicitudes en un servlet o manteniendo un conjunto de instancias de servlet. Si el servlet es parte de una aplicación web que se ha marcado como distribuible, el contenedor puede mantener un conjunto 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 envían al método de servicio de la clase abstracta HttpServlet) se ha definido con la palabra clave sincronizada, el contenedor de servlet no puede usar el enfoque de grupo de instancia , pero debe serializar las solicitudes a través de él. Se recomienda encarecidamente a los desarrolladores que no sincronicen el método de servicio (o los métodos que se le envían) en estas circunstancias debido a los efectos perjudiciales sobre el rendimiento.

    No. Los servlets no son seguros

    The is permite acceder a más de un hilo a la vez

    si quieres que sea Servlet como Thread safe., U puede ir por

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

    métodos

    o podemos ir por métodos de sincronización

    podemos hacer que todo el método de servicio esté sincronizado mediante el uso sincronizado

    keword delante del método

    Ejemplo::

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

    o podemos poner el bloque del código en el bloque sincronizado

    Ejemplo::

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

    Siento que el locking sincronizado es mejor que hacer todo el método

    Sincronizado