2016-07-12 5 views
0

Я обновил tomcat с версии 7.0.34 до версии 8.0.33, и с тех пор у меня возникла проблема с совместным использованием контекста веб-приложения и контекста Junit.shared classloader со встроенным Tomcat 8

У меня есть веб-приложение с классом singleton, которое собирает статистические данные о веб-приложении. У меня также есть Junit, который запускает веб-приложение во встроенном tomcat. Junit запрашивает веб-приложение, а затем проверяет статистические данные.

Я пытаюсь сделать простой пример:

одноточечное:

public class Counter { 

    private static Counter instance; 
    private AtomicLong counter; 

    private Counter(){} 

    public static Counter getInstance(){ 
    if(instance == null){ 
     synchronized (Counter.class) { 
     if(instance == null){ 
      instance = new Counter(); 
     } 
     } 
    } 

    return instance; 
    } 

    public long incrementAndGet(){ 
    return counter.incrementAndGet(); 
    } 

    public long getValue(){ 
    return counter.get(); 
    } 

} 

сервлет:

@WebServlet(name="servlet",loadOnStartup=1, urlPatterns="/servletTest") 
public class Servlet extends HttpServlet{ 

    @Override 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
     resp.getWriter().write("Hi, you are the #" + Counter.getInstance().incrementAndGet() + " visitor"); 
    } 
} 

contextListener:

public class MyContextListener implements ServletContextListener{ 
    @Override 
    public void contextDestroyed(ServletContextEvent arg0) {} 

    @Override 
    public void contextInitialized(ServletContextEvent arg0) { 
    Counter.getInstance().incrementAndGet(); 
    } 
} 

Тест блок:

public void mainTest() throws ServletException, LifecycleException{ 
    Tomcat tomcat = new Tomcat(); 

    tomcat.setPort(50000); 
    StandardContext ctx = (StandardContext) tomcat.addWebapp("/fe", System.getProperty("FEBaseDir")); //The FEBaseDir property is supposed to be taken from Maven build using 'test' profile 

    tomcat.start(); 

    Counter.getInstance().getValue(); 

    } 

Когда я использовал Tomcat 7, все работало нормально. но так как я обновил tomcat до tomcat 8.0.33, он не работает. одноэлементный класс со статическими данными загружается дважды. сначала кота, а затем самого Джунта.

Я попытался передать tomcat загрузчик классов, но он не работает.

public void mainTest() throws ServletException, LifecycleException{ 
    Tomcat tomcat = new Tomcat(); 

    tomcat.setPort(50000); 
    StandardContext ctx = (StandardContext) tomcat.addWebapp("/fe", System.getProperty("FEBaseDir")); //The FEBaseDir property is supposed to be taken from Maven build using 'test' profile 

    ctx.setCrossContext(true); 
    ctx.setLoader((Loader) new WebappLoader(Thread.currentThread().getContextClassLoader())); 

    ctx.setParentClassLoader(Thread.currentThread().getContextClassLoader()); 

    tomcat.getEngine().setParentClassLoader(Thread.currentThread().getContextClassLoader()); 
    tomcat.getHost().setParentClassLoader(Thread.currentThread().getContextClassLoader()); 
    tomcat.getService().setParentClassLoader(Thread.currentThread().getContextClassLoader()); 
    tomcat.getServer().setParentClassLoader(Thread.currentThread().getContextClassLoader()); 
    tomcat.start(); 

    Counter.getInstance().getValue(); 

    } 

Что я делаю неправильно?

ответ

0

Вы могли бы попробовать использовать метод setDelegate в StandardContext, чтобы предотвратить веб-приложение из загрузчика классов перезагрузки Counter класса, но это безопасность влияет на плохой форме так совет, который я против этого.
Обычный способ отображения статистики - использовать JMX (MBeans). Вы включаете это, вызывая метод setUseNaming в StandardContext со значением true.

Вы можете зарегистрировать MBean как это (скопированный из here):

MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); 
ObjectName beanPoolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + poolName + ")"); 
mBeanServer.registerMBean(hikariPool, beanPoolName); 

И вы можете получить значение, как это (скопированный из here):

MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); 
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (foo)"); 
HikariPoolMXBean poolProxy = JMX.newMXBeanProxy(mBeanServer, poolName, HikariPoolMXBean.class); 

int idleConnections = poolProxy.getIdleConnections(); 

Смотрите также this SO question и вам Вероятно, вам придется прочитать дополнительную документацию (по моему опыту, требуется некоторое время, чтобы понять всю вещь JMX и заставить ее работать). Я не пробовал это в сочетании с модульными тестами, хотя, поэтому YMMV.