GWT dev-mode外部服务器类加载器地狱(艰难)

时间:2013-01-05 06:44:24

标签: java eclipse gwt servlets jetty

我有两个eclipse项目(在同一个工作区中),一个是运行jetty实例的标准java项目。另一个是GWT项目。 GWT项目(在文件系统上)作为java项目中的webapp存在,并由jetty(xml)配置加载。

我在调试时通过eclipse运行,首先我将jetty服务器作为常规java应用程序(localhost:8080)启动,然后将GWT项目作为“Web应用程序(在外部服务器上)”启动。

除了尝试演员课以外,一切都很有效。在某些情况下,我得到java.lang.ClassCastException。经过几个小时的调试后,我确定这是因为使用了两个单独的类加载器,每个加载器都有一个。

我认为这源于在servlet上下文中创建的对象和那些不是。

的对象

我创建了一个测试来展示这一点。假设从传入请求到servlet调用以下方法,参数instanceOfClassA在servlet请求处理程序中的某处创建并传递给此方法:

public void calledFromServlet(ClassA instanceOfClassA){

    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    // systemClassLoader is sun.misc.Launcher$AppClassLoader@45a877

    Object classA1 = new ClassA();
    ClassLoader loader1 = classA1.getClass().getClassLoader();
    // loader1 is is WebAppClassLoader=GWTProject@b98fe1


    ClassLoader loader2 = instanceOfClassA.getClass().getClassLoader();
    // loader2 is sun.misc.Launcher$AppClassLoader@45a877

    ClientA request = (ClassA)instanceofClassA; // java.lang.ClassCastException!
}

正如您所希望的那样,在当前上下文中创建的对象由WebAppClassLoader = GWTProject @ b98fe1加载,并且servlet上下文中创建的对象(在其他地方)由系统加载程序sun.misc.Launcher $ AppClassLoader加载@ 45a877。

因此,当我尝试将在servlet上下文中创建的对象转换为LITERALLY当前上下文中的同一个类时,我得到一个ClassCastException。

毋庸置疑,这真的毁了我的一周,我无法解决问题,因为我需要能够投射对象。

以前有人经历过这个并有解决方案吗?

更新(1月5日上午2:24):我尝试使用Thread.currentThread()强制当前线程的类加载器.setContextClassLoader(ClassLoader.getSystemClassLoader())。仍然行不通。

更新(1月6日1:09 pm - Thomas Boyer)

似乎有两个感兴趣的线程正在运行,其中一个是我的断点所在:

Thread [38] (Suspended (breakpoint at line 53 in CollaborationSocketListener))  
CollaborationSocketListener.onMessage(String) line: 53  
WebSocketConnectionRFC6455$WSFrameHandler.onFrame(byte, byte, Buffer) line: 845 
WebSocketParserRFC6455.parseNext() line: 359    
WebSocketServletConnectionRFC6455(WebSocketConnectionRFC6455).handle() line: 235    
SelectChannelEndPoint.handle() line: 606    
SelectChannelEndPoint$1.run() line: 46  
QueuedThreadPool.runJob(Runnable) line: 603 
QueuedThreadPool$3.run() line: 538  
Thread.run() line: 662  

另一个由gwt-dev启动器拥有:

 com.google.gwt.dev.DevMode at localhost:37240  
    Thread [main] (Running) 
Thread [Thread-0] (Running) 
Daemon Thread [Thread-1] (Running)  
Daemon Thread [UnitWriteThread] (Running)   
Daemon Thread [Timer-0] (Running)   
Daemon Thread [Code server listener] (Running)  
Daemon Thread [com.google.gwt.thirdparty.guava.common.base.internal.Finalizer] (Running)    
Daemon Thread [com.google.inject.internal.util.$Finalizer] (Running)    
Daemon Thread [Code server for freshgwtp from Mozilla/5.0 (X11; Linux i686)     AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11 on http://localhost:8080/FreshGWTP.html?gwt.codesvr=127.0.0.1:9997 @ h`"*x.nukanE_ke_] (Running)   

被调用的方法是响应传入servlet的消息(WebSocket servelet)。相关代码在这里:

public void onMessage(String serRequest) {

        // Create a request here to show that we can cast anything created in this context
    Object uFakeRequest = new ClientConnectRequest("someSite", new Client("SomeClient"));

    // This cast works fine
    ClientConnectRequest fakeRequest = (ClientConnectRequest)uFakeRequest;

            // Now I build the same object from a serialized object using a "deserializer" instantiated elsewhere (Note what it is instantiated does not seem to make a difference
    Object uRequest = streamer.fromString(serRequest);

            // ClassCastException
    ClientConnectRequest request = (ClientConnectRequest)uRequest;

    CollaborationSite site = siteManager.getOrCreateSite(request.getSiteID());

    site.onRequestRecieved(con, request);
}

“流光”是一个gwt-streamer(详情请参阅谷歌代码),我尝试在servelet init()中实例化,以及在此方法中内联,并通过Guice注入。我总是得到相同的类强制转换异常。

原因是流媒体的类加载器是系统类加载器,而当前方法中的类加载器是GWT-Dev类加载器。

**更新(1月5日下午2:36)更多混乱**

为了分离类加载器之间的冲突,我启动了两个单独的eclipse实例,在一个中启动了jetty app,在另一个上启动了gwt-dev模式(在外部服务器上)。仍然得到相同的错误。

我不明白为什么GWT认为应该在外部服务器的服务器端代码处理类加载......

0 个答案:

没有答案