J'ai plusieurs applications Web exécutées sur un serveur d'applications et chaque fichier WAR d'application Web contient une copie du même fichier JAR.
Est-ce à dire qu'une classe de ce fichier jar sera chargée plusieurs fois dans la JVM, une fois pour chaque fichier WAR dans lequel elle existe? Suite à cela, si j'ai une méthode synchronisée statique dans une telle classe, est-elle uniquement synchronisée entre les threads au sein de l'application Web dans laquelle elle existe mais pas synchronisée avec la même méthode dans la même classe dans un fichier jar différent dans un autre Fichier WAR? (J'espère que la question a du sens, clarifiera si nécessaire).
Si tel est le cas, je suppose que la meilleure solution consiste à supprimer le fichier jar de chaque fichier WAR et à le déployer dans un dossier de chemin de classe partagé sur le serveur?
A Java classloader fonctionne généralement en recherchant des classes à un ou plusieurs endroits dans une séquence fixe. Par exemple, le classloader qui charge votre application lorsque vous l'exécutez à partir de la ligne de commande regarde d'abord dans le rt.jar
fichier (et d'autres sur le bootclasspath), puis dans les répertoires et fichiers JAR spécifiés par votre classpath.
Un chargement de classe webapp est similaire en principe, mais un peu plus compliqué en pratique. Pour une webapp particulière, le chargeur de classe d'une webapp recherche les classes dans l'ordre suivant. Par exemple, Tomcat 6 recherche les classes dans cet ordre:
Bien sûr, une fois que le chargeur de classe a trouvé la classe qu'il recherche, il ne cherche plus. Ainsi, les classes portant le même nom plus tard dans l'ordre ne seront pas chargées.
La complication est que le conteneur Web a un chargeur de classe pour chaque application Web, et ces chargeurs de classe délèguent à d'autres chargeurs de classe qui gèrent les classes communes. En pratique, cela signifie que certaines classes ne seront jamais chargées qu'une seule fois pour l'ensemble du conteneur (par exemple, 1. et 2.) et d'autres peuvent être chargées plusieurs fois par différents chargeurs de classe.
(Lorsqu'une classe est chargée plus d'une fois, il en résulte des objets Class
et des statiques de classe distincts. Les versions de la classe sont de types différents en ce qui concerne la JVM et vous ne pouvez pas transtyper une version en une autre.)
Enfin, Tomcat peut être configuré pour permettre aux applications Web individuelles d'être "chargées à chaud". Cela implique d'arrêter une application Web, de créer un nouveau chargeur de classe et de la redémarrer.
[~ # ~] suivi [~ # ~]
Donc ... la synchronisation d'une méthode statique ne protégera pas l'accès à une ressource partagée où la classe a été chargée plusieurs fois?
Cela dépend des détails, mais ce ne sera probablement pas le cas. (Ou pour voir si d'une autre manière, si une classe a en fait a été chargée plusieurs fois, alors une méthode static
de chaque "charge" de la classe accédera à un ensemble différent des champs static
.)
Si vous voulez vraiment qu'une instance de classe d'application singleton soit partagée par plusieurs webapps dans le même conteneur, c'est plus simple si vous mettez la classe dans $CATALINA_HOME/lib
ou l'équivalent. Mais vous devez également vous demander si c'est une bonne conception du système. Envisagez de combiner les applications Web ou d'utiliser le transfert de demande, etc. au lieu d'une structure de données partagée. Le modèle singleton a tendance à être gênant dans les applications Web, et cette saveur l'est encore plus.
Les serveurs d'applications Java EE utilisent généralement plusieurs chargeurs de classe pour isoler les applications les unes des autres et permettre le déploiement de nouvelles versions d'une application sans affecter les autres applications.
Vous obtenez des modèles tels que plusieurs fichiers WAR et un fichier EJB dans un EAR avec une hiérarchie de chargeurs de classe, chaque WAR ayant son propre.
Cela mène à la duplication comme vous le décrivez, mais ce n'est pas nécessairement une mauvaise chose. Cela signifie que vous pouvez même déployer simultanément différentes versions des mêmes fichiers JAR, ce qui peut en fait être bénéfique, permettant une migration incrémentielle vers de nouvelles versions.
Certains serveurs d'applications (WebSphere pour exmaple) ont un support explicite pour un concept de bibliothèque partagée, et je l'utilise.
Méfiez-vous de simplement insérer des fichiers JAR dans des chemins de classe arbitraires, vous courez le risque de déstabiliser le serveur d'application lui-même.
La plupart des serveurs d'applications utilisent la plus spécifique le long d'un chemin a priorité stratégie. Si vous avez plusieurs bibliothèques qui font la même chose, vous devriez envisager de les mettre dans la bibliothèque du serveur d'applications (par exemple: Tomcat_HOME/lib)