1239 votes

Comment fonctionnent les servlets ? Instanciation, sessions, variables partagées et multithreading

Supposons que j'ai un serveur Web qui contient de nombreux servlets. Pour le transfert d'informations entre ces servlets, je définis des variables de session et d'instance.

Maintenant, si 2 utilisateurs ou plus envoient une requête à ce serveur, qu'arrive-t-il aux variables de session ?
Seront-elles communes à tous les utilisateurs ou différentes pour chacun d'entre eux ?
S'ils sont différents, alors comment le serveur a-t-il pu différencier les différents utilisateurs ?

Une autre question similaire, s'il y a n utilisateurs accédant à un servlet particulier, alors ce servlet est instancié uniquement la première fois que le premier utilisateur y accède ou est-il instancié pour tous les utilisateurs séparément ?
En d'autres termes, que deviennent les variables d'instance ?

1930voto

BalusC Points 498232

ServletContext

Lorsque le conteneur de servlets (comme Apache Tomcat ) démarre, il va déployer et charger toutes ses applications web. Lorsqu'une application Web est chargée, le conteneur de servlets crée l'attribut ServletContext une fois et le conserve dans la mémoire du serveur. L'application web web.xml et tout ce qui est inclus web-fragment.xml est analysé, et chaque <servlet> , <filter> y <listener> trouvé (ou chaque classe annotée avec @WebServlet , @WebFilter y @WebListener respectivement) seront instanciés une fois et seront également conservés dans la mémoire du serveur, enregistrés via la propriété ServletContext . Pour chaque filtre instancié, son init() est invoquée avec une nouvelle FilterConfig qui contient à son tour l'argument ServletContext .

Lorsqu'un Servlet a un <servlet><load-on-startup> o @WebServlet(loadOnStartup) valeur supérieure à 0 alors son init() est également invoquée lors du démarrage avec une nouvelle méthode ServletConfig qui contient à son tour l'argument ServletContext . Ces servlets sont initialisés dans l'ordre spécifié par cette valeur ( 1 est le premier, 2 est 2ème, etc). Si la même valeur est spécifiée pour plus d'une servlet, chacune de ces servlets est chargée dans l'ordre dans lequel elle apparaît dans le fichier web.xml , web-fragment.xml ou @WebServlet le chargement des classes. Dans le cas où la valeur "load-on-startup" est absente, la classe init() sera invoquée chaque fois que la méthode Demande HTTP frappe ce servlet pour la toute première fois.

Lorsque le conteneur de servlets a terminé toutes les étapes d'initialisation décrites ci-dessus, alors la fonction ServletContextListener#contextInitialized() sera invoqué avec un ServletContextEvent qui contient à son tour l'argument ServletContext . Cela donnera au développeur la possibilité d'enregistrer de façon programmatique une autre Servlet , Filter o Listener .

Lorsque le conteneur de servlets s'arrête, il décharge toutes les applications Web, invoque la fonction de contrôle de l'accès à l'information de l'entreprise. destroy() de toutes ses servlets et filtres initialisés, et toutes les méthodes Servlet , Filter y Listener enregistrées par l'intermédiaire de la ServletContext sont mis à la poubelle. Enfin, le ServletContextListener#contextDestroyed() sera invoqué et le ServletContext lui-même sera mis à la poubelle.

HttpServletRequest y HttpServletResponse

Le conteneur de servlets est attaché à un serveur web qui écoute les demandes HTTP sur un certain numéro de port (le port 8080 est généralement utilisé pendant le développement et le port 80 en production). Lorsqu'un client (par exemple, un utilisateur avec un navigateur Web, ou de manière programmatique en utilisant URLConnection ) envoie une requête HTTP, le conteneur de servlets crée de nouvelles HttpServletRequest y HttpServletResponse et les fait passer par tout objet défini Filter dans la chaîne et, finalement, le Servlet instance.

Dans le cas de filtres El doFilter() est invoquée. Lorsque le code du conteneur de servlet appelle chain.doFilter(request, response) la demande et la réponse passent au filtre suivant, ou au servlet s'il n'y a plus de filtres.

Dans le cas de servlets El service() est invoquée. Par défaut, cette méthode détermine quel est l'un des éléments suivants doXxx() les méthodes à invoquer en fonction de request.getMethod() . Si la méthode déterminée est absente de la servlet, alors une erreur HTTP 405 est renvoyée dans la réponse.

L'objet de requête permet d'accéder à toutes les informations relatives à la requête HTTP, comme son URL , en-têtes , chaîne de requête et le corps. L'objet response permet de contrôler et d'envoyer la réponse HTTP comme vous le souhaitez, par exemple en vous permettant de définir les en-têtes et le corps (généralement avec du contenu HTML généré à partir d'un fichier JSP). Lorsque la réponse HTTP est validée et terminée, les objets requête et réponse sont recyclés et peuvent être réutilisés.

HttpSession

Lorsqu'un client visite la webapp pour la première fois et/ou la HttpSession est obtenu pour la première fois via request.getSession() le conteneur de servlets crée un nouveau HttpSession génère un ID long et unique (que vous pouvez obtenir par session.getId() ), et le stocke dans la mémoire du serveur. Le conteneur de servlets définit également un Cookie dans le Set-Cookie de la réponse HTTP avec JSESSIONID comme son nom et l'ID de session unique comme sa valeur.

Conformément à la Spécification des cookies HTTP (un contrat que tout navigateur web et serveur web décent doit respecter), le client (le navigateur web) est tenu d'envoyer cet cookie dans les demandes ultérieures dans le Cookie tant que le cookie est valide (c'est-à-dire que l'ID unique doit faire référence à une session non expirée et que le domaine et le chemin sont corrects). À l'aide du moniteur de trafic HTTP intégré à votre navigateur, vous pouvez vérifier que le cookie est valide (appuyez sur F12 dans Chrome / Firefox 23+ / IE9+, et vérifiez l'en-tête Net/Network tab). Le conteneur de servlets vérifiera le Cookie de chaque requête HTTP entrante pour la présence du cookie avec le nom JSESSIONID et utiliser sa valeur (l'identifiant de la session) pour obtenir l'identifiant de l'utilisateur associé. HttpSession de la mémoire du serveur.

El HttpSession reste en vie jusqu'à ce qu'il soit inactif (c'est-à-dire qu'il n'ait pas été utilisé dans une requête) pendant une durée supérieure à la valeur de délai d'attente spécifiée dans le champ <session-timeout> un cadre dans web.xml . La valeur par défaut du délai d'attente est de 30 minutes. Ainsi, lorsque le client ne visite pas l'application Web pendant une période plus longue que celle spécifiée, le conteneur de servlets met à la poubelle l'application Web. session . Chaque demande ultérieure, même avec le cookie spécifié, n'aura plus accès à la même session ; le conteneur de servlets créera une nouvelle session.

Du côté client, le cookie de session reste actif aussi longtemps que l'instance du navigateur est en cours d'exécution. Ainsi, si le client ferme l'instance du navigateur (tous les onglets/fenêtres), la session est mise à la poubelle du côté du client. Dans une nouvelle instance du navigateur, le cookie associé à la session n'existe plus et n'est donc plus envoyé. Cela entraîne une toute nouvelle HttpSession pour être créé, un cookie de session entièrement nouveau étant utilisé.

En bref

  • El ServletContext vit aussi longtemps que l'application web vit. Elle est partagée entre tous demandes en tous sessions.
  • El HttpSession vit tant que le client interagit avec l'application web avec la même instance de navigateur, et que la session n'a pas expiré du côté du serveur. Elle est partagée entre tous demandes dans le même session.
  • El HttpServletRequest y HttpServletResponse vivent à partir du moment où la servlet reçoit une requête HTTP du client, jusqu'à ce que la réponse complète (la page web) soit arrivée. Il s'agit no partagé ailleurs.
  • Tous Servlet , Filter y Listener Les instances vivent aussi longtemps que l'application web. Elles sont partagées entre tous demandes en tous sessions.
  • Tout attribute qui est défini dans ServletContext , HttpServletRequest y HttpSession vivra aussi longtemps que l'objet en question vivra. L'objet lui-même représente la "portée" dans les cadres de gestion des haricots tels que JSF, CDI, Spring, etc. Ces frameworks stockent leurs beans scopés sous la forme d'un objet attribute de sa portée la plus proche.

Sécurité du fil

Cela dit, votre principale préoccupation est peut-être sécurité du fil . Vous devriez maintenant savoir que les servlets et les filtres sont partagés entre toutes les requêtes. C'est l'avantage de Java : il est multithread et différents threads (lire : requêtes HTTP) peuvent utiliser la même instance. Sinon, il serait trop coûteux de la recréer, init() y destroy() pour chaque demande.

Vous devez également réaliser que vous devez nunca assigner toute donnée de demande ou de session en tant qu'un instance d'une servlet ou d'un filtre. Elle sera partagée entre toutes les autres requêtes des autres sessions. C'est no sans risque pour les fils ! L'exemple ci-dessous l'illustre :

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

Voir aussi :

26 votes

Donc, si j'arrive à trouver le JSessionId qui est envoyé à un client, je peux voler sa session ?

56 votes

@Toskan : c'est exact. C'est connu sous le nom de hack de fixation de session . Veuillez noter que ceci n'est pas spécifique à JSP/Servlet. Tous les autres langages côté serveur qui maintiennent la session par un cookie sont également sensibles, comme PHP avec PHPSESSID cookie, ASP.NET avec ASP.NET_SessionID cookie, etcetera. C'est également la raison pour laquelle la réécriture d'URL avec ;jsessionid=xxx comme le font automatiquement certains frameworks JSP/Servlet MVC est mal vu. Assurez-vous simplement que l'ID de session n'est jamais exposé dans l'URL ou par d'autres moyens dans les pages Web, afin que l'utilisateur final non averti ne soit pas attaqué.

12 votes

@Toskan : Assurez-vous également que votre webapp n'est pas sensible aux attaques XSS. Par exemple, ne réaffichez pas les données contrôlées par l'utilisateur sous une forme non codée. Les XSS ouvrent la porte à des moyens de collecter les identifiants de session de tous les utilisateurs finaux. Voir aussi Quel est le concept général derrière XSS ?

442voto

Jops Points 6734

Sessions

enter image description hereenter image description here

En bref : le serveur web émet un identifiant unique pour chaque visiteur sur son premièrement visite. Le visiteur doit rapporter cet identifiant pour qu'il soit reconnu lors de sa prochaine visite. Cet identifiant permet également au serveur de séparer correctement les objets appartenant à une session de ceux d'une autre session.

Instanciation des servlets

Si Chargement au démarrage es faux :

enter image description hereenter image description here

Si Chargement au démarrage es vrai :

enter image description hereenter image description here

Une fois qu'il est sur le mode service et sur le sillon, la même fonctionnera sur les requêtes de tous les autres clients.

enter image description here

Pourquoi n'est-ce pas une bonne idée d'avoir une instance par client ? Pensez-y : Allez-vous engager un pizzaïolo pour chaque commande qui arrive ? Faites cela et vous feriez faillite en un rien de temps.

Il y a cependant un petit risque. Rappelez-vous : ce seul homme détient toutes les informations relatives à la commande dans sa poche : donc si vous n'êtes pas prudent à propos de sécurité des threads sur les servlets il peut finir par donner la mauvaise commande à un certain client.

27 votes

Votre photo est très bonne pour ma compréhension. J'ai une question, que va faire cette pizzeria quand trop de commandes de pizzas arrivent, juste attendre un pizzaïolo ou engager plus de pizzaïolo ? Merci.

7 votes

Il renverra un message avec to many requests at this moment. try again later

4 votes

Les servlets, contrairement aux livreurs de pizzas, peuvent effectuer plus d'une livraison en même temps. Ils doivent juste faire attention à l'endroit où ils inscrivent l'adresse du client, la saveur de la pizza...

42voto

Chris Thompson Points 18375

La session dans les servlets Java est la même que la session dans d'autres langages comme le PHP. Elle est unique à l'utilisateur. Le serveur peut en garder la trace de différentes manières telles que les cookies, la réécriture d'url, etc. Ce site Doc Java l'explique dans le contexte des servlets Java et indique que la manière exacte dont la session est maintenue est un détail de mise en œuvre laissé aux concepteurs du serveur. La spécification stipule seulement que la session doit être maintenue comme unique pour un utilisateur à travers de multiples connexions au serveur. Consultez le site cet article d'Oracle pour plus d'informations sur vos deux questions.

Modifier Il existe un excellent tutoriel aquí sur la façon de travailler avec les sessions dans les servlets. Et aquí est un chapitre de Sun sur les Java Servlets, ce qu'ils sont et comment les utiliser. Entre ces deux articles, vous devriez être en mesure de répondre à toutes vos questions.

0 votes

Cela soulève une autre question pour moi, puisqu'il n'y a qu'un seul contexte de servlet pour l'ensemble de l'application et que nous avons accès aux variables de session par le biais de ce contexte de servlet, alors comment les variables de session peuvent-elles être uniques pour chaque utilisateur ? Merci

1 votes

Comment accédez-vous à la session depuis le servletContext ? Vous ne faites pas référence à servletContext.setAttribute(), n'est-ce pas ?

5 votes

@KuJon Chaque application web a une ServletContext objet. Cet objet possède zéro, un ou plusieurs objets session -- une collection d'objets session. Chaque session est identifiée par une sorte de chaîne d'identification, comme on le voit dans les dessins animés sur d'autres réponses. Cet identifiant est suivi sur le client par un cookie ou une réécriture d'URL. Chaque objet de session possède ses propres variables.

33voto

Ajay Thakur Points 625

Lorsque le conteneur de servlets (comme Apache Tomcat) démarre, il lit le fichier web.xml (un seul par application) si quelque chose ne va pas ou affiche une erreur dans la console du conteneur, sinon, il déploie et charge toutes les applications web en utilisant web.xml (appelé ainsi comme descripteur de déploiement).

Pendant la phase d'instanciation de la servlet, l'instance de la servlet est prête mais elle ne peut pas répondre à la demande du client car il lui manque deux informations :
1 : information sur le contexte

Le moteur de servlet crée l'objet d'interface servletConfig en y encapsulant les informations manquantes ci-dessus Le moteur de servlet appelle init() de la servlet en fournissant les références de l'objet servletConfig comme argument. Une fois que la fonction init() est complètement exécutée, la servlet est prête à répondre à la demande du client.

Q) Pendant la durée de vie d'une servlet, combien de fois l'instanciation et l'initialisation ont-elles lieu ?

A)une seule fois (un nouveau fil est créé pour chaque demande du client) une seule instance de la servlet répond à n'importe quel nombre de demandes de clients, c'est-à-dire qu'après avoir répondu à une demande de client, le serveur ne meurt pas. Il attend d'autres demandes de clients, c'est-à-dire que la limitation du CGI (pour chaque demande de client, un nouveau processus est créé) est surmontée par la servlet (le moteur de servlet crée le fil en interne).

Q)Comment fonctionne le concept de session ?

A)chaque fois que getSession() est appelé sur l'objet HttpServletRequest

Étape 1 L'objet de la demande est évalué pour l'ID de la session entrante.

Étape 2 si l'ID n'est pas disponible, un tout nouvel objet HttpSession est créé et son ID de session correspondant est généré (c'est-à-dire de HashTable) l'ID de session est stocké dans l'objet de réponse httpservlet et la référence de l'objet HttpSession est renvoyée à la servlet (doGet/doPost).

Étape 3 si l'ID est disponible, un nouvel objet de session n'est pas créé l'ID de la session est récupéré dans l'objet de la demande la recherche est faite dans la collection de sessions en utilisant l'ID de la session comme clé.

Une fois la recherche réussie, l'ID de la session est stocké dans HttpServletResponse et les références de l'objet de session existant sont renvoyées à la doGet() ou doPost() de UserDefineservlet.

Note :

1) Lorsque le contrôle passe du code de la servlet au client, n'oubliez pas que l'objet de session est conservé par le conteneur de la servlet, c'est-à-dire le moteur de la servlet.

2) le multithreading est laissé aux développeurs de servlets pour l'implémenter, c'est-à-dire pour gérer les multiples requêtes du client sans se soucier du code multithread.

Forme courte :

Une servlet est créée au démarrage de l'application (elle est déployée sur le conteneur de servlets) ou lors du premier accès (selon le paramètre load-on-startup). lors de l'instanciation de la servlet, la méthode init() de la servlet est appelée puis la servlet (sa seule et unique instance) traite toutes les requêtes (sa méthode service() étant appelée par plusieurs threads). C'est pourquoi il n'est pas conseillé d'avoir une quelconque synchronisation dans la servlet, et il faut éviter les variables d'instance de la servlet lorsque l'application n'est pas déployée (le conteneur de servlets s'arrête), la méthode destroy() est appelée.

21voto

Lauri Lehtinen Points 5417

Sessions - ce que Chris Thompson a dit.

Instanciation - une servlet est instanciée lorsque le conteneur reçoit la première requête mappée à la servlet (à moins que la servlet ne soit configurée pour se charger au démarrage avec l'attribut <load-on-startup> élément dans web.xml ). La même instance est utilisée pour servir les demandes suivantes.

3 votes

Correct. Réflexion supplémentaire : À chaque demande, un nouveau thread (ou un thread recyclé) est lancé sur cette instance unique de Servlet. Chaque Servlet possède une instance, et éventuellement plusieurs threads (si plusieurs requêtes simultanées).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X