Поведение Classloader на Tomcat с несколькими приложениями

На сервере Tomcat 5.5 я помещаю класс в системный путь к классам (и изменяю Catalina.bat, чтобы выбрать его), или если я помещаю класс в каталог общей библиотеки lib. Теперь, если у меня есть два разных приложения, использующих тот же класс, который не имеет класса в своих каталогах lib/classes WEB-INF, они используют один и тот же экземпляр класса. Я понимаю, что classloader будет делегировать ему родительский загрузчик классов для поиска класса, если он не может его найти, поэтому в этом случае, поскольку класс отсутствует в WEB-INF/classes или WEB-INF/lib, Загрузчик классов WebAppX будет использовать общий, общий и системный загрузчик классов соответственно.

Однако мне как-то кажется странным, что два разных приложения могут использовать контекст, используя этот метод. Может ли кто-нибудь помочь мне понять, почему это так. например в нижнем коде два сервлета развертываются в отдельных войнах, в то время как CommonCounter является общим, и они могут считывать значения счетчика, увеличенные другим.

Edit Мне кажется, что интуитивно понятно, что два отдельных приложения могут использовать контекст таким образом. Фактически, если у них есть один и тот же экземпляр класса, они могут даже реализовать многопоточность/синхронизацию в двух разных приложениях, что кажется чрезвычайно противоречивым.

package com.test;
public class CommonCounter {

    public static int servlet1;
    public static int servlet2;
}




public class Servlet1 extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        CommonCounter.servlet1++;
        System.out.println("Other one had "+CommonCounter.servlet2+" hits");
    }   
}



public class Servlet2 extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        CommonCounter.servlet2++;
        System.out.println("Other one had "+CommonCounter.servlet1+" hits");
    }   
}

Ответ 1

Как следует из комментариев, вы правильно объяснили, почему вы наблюдаете поведение, которое вы наблюдаете.

Ключ структурирован ClassLoaders. Вполне возможно для двух ClassLoaders в пределах одной JVM для каждой загрузки класса и, следовательно, содержит отдельные независимые копии статических полей. "static" делает что-то "глобальное" для ClassLoader, а не для JVM. Tomcat, я полагаю, не смог удержать ClassLoader на уровне контейнера с общими библиотеками и каким-то образом заставить каждое приложение ClassLoader загружать разделяемые библиотеки отдельно.

Но это будет немного расточительно для других распространенных классов, таких как API и реализация J2EE. В принципе, классы не должны зависеть от этой структуры ClassLoader.

Вот почему вы не должны устанавливать зависимости приложений в папках разделяемой библиотеки Tomcat. Это "решение". Он связывает ваше приложение с конкретными настройками и развертыванием контейнера, что противоречит принципу веб-приложений J2EE. Просто поместите копии зависимостей в WEB-INF/lib для каждого приложения.

Поведение, которое вы наблюдаете, является еще одной причиной не делать этого: приложения становятся менее изолированными друг от друга. Это не влияет на меня как на интуитивное поведение, но я полагаю, только потому, что я привык к тому, как Томкат работает и думает об этом.