2016-07-12 37 views
0

Ich habe tomcat von Version 7.0.34 auf Version 8.0.33 aktualisiert, und seitdem habe ich ein Problem, den Webanwendungskontext und Junit-Kontext zu teilen.shared Classloader mit integriertem Tomcat 8

Ich habe eine Webanwendung mit Singleton-Klasse, die statistische Daten über die Webanwendung sammelt. Ich habe auch Junit, der die Webanwendung in Embedded Tomcat ausführt. Der Junit fragt die Webanwendung ab und überprüft dann die Statistikdaten.

Ich versuche, ein einfaches Beispiel zu machen:

die Singletons:

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

} 

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

Prüfgerät:

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

    } 

Wenn ich Tomcat 7 verwendet habe, hat alles gut funktioniert. Aber seit ich Tomcat 8.0.33 zu Tomcat upgraded, hat es nicht funktioniert. Die Singleton-Klasse mit den statischen Daten wird zweimal geladen. zuerst beim Kater und dann beim Junit.

Ich habe versucht, Tomcat ein Classloader zu übergeben, aber es funktioniert nicht.

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

    } 

Was mache ich falsch?

Antwort

0

Sie könnten versuchen, die setDelegate Methode in StandardContext über die Web-App-Classloader zu verhindern, dass die Counter Klasse Nachladen, aber diese Auswirkungen Sicherheit in einer schlechten Art und Weise, damit ich Rat dagegen.
Die übliche Methode, Statistiken anzuzeigen, ist die Verwendung von JMX (MBeans). Sie aktivieren dies, indem Sie die Methode setUseNaming in StandardContext mit dem Wert true aufrufen.

Sie können eine mbean wie dieses Register (kopiert von here):

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

Und Sie können einen Wert wie folgt (von here kopiert) abrufen:

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

Siehe auch this SO question und Sie Ich werde wahrscheinlich noch mehr Dokumentation lesen müssen (meiner Erfahrung nach dauert es eine Weile, um das ganze JMX-Ding zu verstehen und es zum Laufen zu bringen). Ich habe dies jedoch nicht in Kombination mit Unit-Tests versucht, also YMMV.