2016-07-12 67 views
0

我已將Tomcat從版本7.0.34升級到版本8.0.33,從那時起我一直面臨着共享Web應用程序上下文和Junit上下文的問題。帶有嵌入式Tomcat的共享類加載器8

我有一個Web應用程序,它有一個收集有關Web應用程序統計數據的單例類。我也有Junit在嵌入式tomcat中運行web應用程序。 Junit查詢Web應用程序,然後檢查統計數據。

我試圖做一個簡單的例子:

單身:

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(); 
    } 

} 

該servlet:

@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,然後由Junit本身。

我試圖通過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

你可以嘗試使用StandardContextsetDelegate方法,以防止在web-app類加載器從重裝Counter類,但在一個糟糕的方式這會影響安全性,以便針對我的意見。
公開統計信息的常用方法是使用JMX(MBeans)。通過調用StandardContext中的值爲truesetUseNaming方法來啓用此功能。

你可以這樣註冊一個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。