码头、websocket、java.lang.RuntimeException:无法加载平台配置器

Posted

技术标签:

【中文标题】码头、websocket、java.lang.RuntimeException:无法加载平台配置器【英文标题】:Jetty, websocket, java.lang.RuntimeException: Cannot load platform configurator 【发布时间】:2017-02-06 00:31:56 【问题描述】:

我尝试在 Endpoint 中获取 http 会话。我遵循了这个建议https://***.com/a/17994303。这就是我这样做的原因:

public class MyConfigurator extends ServerEndpointConfig.Configurator

    @Override
    public void modifyHandshake(ServerEndpointConfig config, 
                                HandshakeRequest request, 
                                HandshakeResponse response)
    
        HttpSession httpSession = (HttpSession)request.getHttpSession();
        config.getUserProperties().put(HttpSession.class.getName(),httpSession);
    

@ServerEndpoint(value = "/foo", configurator = MyConfigurator.class)
public class MyEndpoint 

    private Session wsSession;

    private HttpSession httpSession;


    @OnOpen
    public void open(final Session session,EndpointConfig config) 
        this.wsSession=session;
        this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
    

这就是我得到的

java.lang.RuntimeException: Cannot load platform configurator
    at javax.websocket.server.ServerEndpointConfig$Configurator.fetchContainerDefaultConfigurator(ServerEndpointConfig.java:123)
    at javax.websocket.server.ServerEndpointConfig$Configurator.getContainerDefaultConfigurator(ServerEndpointConfig.java:128)
    at javax.websocket.server.ServerEndpointConfig$Configurator.checkOrigin(ServerEndpointConfig.java:192)
    at org.eclipse.jetty.websocket.jsr356.server.JsrCreator.createWebSocket(JsrCreator.java:88)
    at org.eclipse.jetty.websocket.server.WebSocketServerFactory.acceptWebSocket(WebSocketServerFactory.java:187)
    at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:207)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1676)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:581)
    at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:70)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1180)
    at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:276)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1112)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
    at org.eclipse.jetty.server.Server.handle(Server.java:524)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:319)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:253)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
    at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)
    at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303)
    at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148)
    at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589)
    at java.lang.Thread.run(Thread.java:745)

我使用 osgi、jetty 9.3.11 和 pax-web 6.0.0。

【问题讨论】:

在您的 OSGi 环境中看起来像 ServiceLoader 问题。 javax.websocket.server.ServerEndpointConfig 使用 ServiceLoader 加载默认配置器(来自 Jetty) 【参考方案1】:

问题在于 javax.websocket-api jar 没有设置为使用 osgi 中的 ServiceLoader 机制,因此它可以找到自定义 Configurator 实例。

为了在 osgi 中工作,javax.websocket-api jar 中的清单需要有以下几行:

Require-Capability: osgi.serviceloader;filter:="(osgi.serviceloader=javax.websocket.server.ServerEndpointConfig.Configurator)";resolution:=optional;cardin
 ality:=multiple,osgi.extender;filter:="(osgi.extender=osgi.serviceloa
 der.processor)"

因此,由于它没有这些行,因此您将需要添加另一个带有清单的包,其中包含这些行,并将自身声明为 javax.websocket-api 包的片段。

如果您使用的是 maven,那么您在 pom 中需要的行类似于:

      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <configuration>
            <instructions>
              <Bundle-SymbolicName>$bundle-symbolic-name;singleton:=true</Bundle-SymbolicName>
              <Bundle-Name>OSGi Websocket API Fragment</Bundle-Name>
              <Fragment-Host>javax.websocket-api</Fragment-Host>
            <Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=)javax.websocket.server.ServerEndpointConfig.Configurator";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)"</Require-Capability>
            </instructions>
        </configuration>
      </plugin>

【讨论】:

感谢您的回答和时间。它没有帮助。我试图将这些行添加到 javax.websocket-api 的清单中。此外,我尝试按照您所说的制作单独的捆绑包。它没有帮助。我有一种感觉 aries.spifly 不适合我。除了添加三个捆绑包asm-all-5.0.4.jar, org.apache.aries.util-1.1.1.jar, org.apache.aries.spifly.dynamic.bundle-1.0.1.jar之外,我可能还需要做更多的事情。 你的答案几乎是正确的。错误在于 Configurator 是嵌套类,所以最后一个 . 必须是 $,而不是最后一个。所以我只是在 javax.websocket-api.jar 的清单中添加了Require-Capability: osgi.extender;filter:="(osgi.extender=osgi.servicelo ader.processor)",osgi.serviceloader;filter:="(osgi.serviceloader=javax. websocket.server.ServerEndpointConfig$Configurator)";resolution:=option al;cardinality:=multiple 能否请您发布有关哪些文件进入 WAR 文件的信息,对于我们这些对 OSGi 不屑一顾的人来说,只是不幸被任务部署到 WAR 文件中卡拉夫?【参考方案2】:

您可以安装 mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.javax-websocket-api/1.1_1 捆绑包,它是原始 javax.websocket-api 的重新打包,但具有正确的 OSGi 描述符。更多信息在这里:http://mavi.logdown.com/posts/7813065-deploying-vaadin-app-on-karaf

【讨论】:

【参考方案3】:

这就是创建我的片段修复的方法:

        <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <extensions>true</extensions>
            <configuration>
                <instructions>
                    <Bundle-SymbolicName>$project.groupId.$project.artifactId;singleton:=true</Bundle-SymbolicName>
                    <Bundle-Name>Websocket API OSGi Fix</Bundle-Name>
                    <Fragment-Host>javax.websocket-api</Fragment-Host>
                    <Require-Capability>
                        osgi.serviceloader;osgi.serviceloader="javax.websocket.server.ServerEndpointConfig$Configurator"
                    </Require-Capability>
                </instructions>
            </configuration>
        </plugin>

【讨论】:

【参考方案4】:

这不是一个答案,但我们认为它可能会帮助遇到与我们相同的问题的其他用户:我们遇到了与 OP 描述的完全相同的问题,但“已接受的答案”并没有解决它。也就是说,我们将描述的条目精确地添加到指定 jar 中的 Manifest 中,并且我们继续得到相同的异常(与 OP 列出的相同)。

我们设法解决了以下问题。在我们的 Dropwizard 的 initialize() 方法中,我们有如下代码:

@Override
public void initialize(Bootstrap<AppConfig> bootstrap) 
   ...
   bootstrap.addBundle(new WebsocketBundle(MyWebsocketHandler.class));
   ...

在跟踪 Dropwizard 代码后,我们发现我们正在调用的 WebsocketBundle 构造函数将 null 分配给默认配置器,尽管 MyWebsocketHandler 类上的 @ServerEndpoint 注释指定了一个配置器类,如下所示:

@ServerEndpoint(value="/myWebsocketPath",configurator=CustomEndpointConfigurator.class)

我们将 initialize() 中的构造函数调用改为

bootstrap.addBundle(new WebsocketBundle(new CustomEndpointConfigurator(), TeamWebsocketHandler.class));

and poof,异常消失了。 (它确实导致了一长串新的“NoClassDefFound”异常,但这些异常很容易找到。安装包含所有缺失类的缺失库后,应用程序 websocket 开始按预期运行。)

完全有可能我们完全误解了 Dropwizard 的工作原理(或应该如何工作);当涉及到这个领域时,我们这些参与这个项目的人都是严肃的新手,我们欢迎任何解释为什么我们所做的事情是“错误的”或“没有意义的”。但我们认为,当“接受的答案”没有发现时,它可能会帮助其他人发现对我们有用的东西。

【讨论】:

【参考方案5】:

在我的例子中,我用 proguard 混淆了 javax.websocket。以下为我解决了这个问题:

-keep class javax.websocket.**  *; 

【讨论】:

以上是关于码头、websocket、java.lang.RuntimeException:无法加载平台配置器的主要内容,如果未能解决你的问题,请参考以下文章

码头 Websocket JSR 356 错误 403

码头 WebSocket 服务器

JAVA 码头 9 Websocket SSL

码头webSocket:java.lang.IllegalStateException:已提交

码头、websocket、java.lang.RuntimeException:无法加载平台配置器

如何使用同一端口(使用码头 8)拥有具有多个上下文的 websocket