Повторно подключающийся веб-сокет не может подключиться к серверу с FacesContext.getCurrentInstance (), разрешенным в null - PullRequest
0 голосов
/ 16 июня 2020

У меня простой Tomcat 8.5.47 со следующими установленными зависимостями.

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.faces</artifactId>
    <version>2.3.9</version>
</dependency>
<dependency>
    <groupId>org.jboss.weld.servlet</groupId>
    <artifactId>weld-servlet</artifactId>
    <version>2.4.8.Final</version>
</dependency>
<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.1</version>
</dependency>

CDI, похоже, работает нормально, или, по крайней мере, я не столкнулся с какими-либо проблемами при переносе @ManagedBean s на @Named. Установленный CDI означает, что я могу ввести PushContext и отправить несколько сообщений с сервера клиенту.

Я объявил простой bean

@ApplicationScoped
@Named("ButtonController")
public class ButtonController implements Serializable {

    @Inject
    @Setter
    @Push(channel = "someChannel")
    private PushContext _someChannel;

    public void onPress() {
        _someChannel.send("...");
    }

}

и канал в шаблоне JSF

<f:websocket channel="someChannel"
             onmessage="_onmessage"
             onopen="_onopen"
             onclose="_onclose"
/>

с обратными вызовами, печатающими консольное сообщение.

<h:outputScript>
    function _onopen() {
        console.log('_onopen')
    }
</h:outputScript>

Когда я загружаю страницу с определенным в ней сокетом, сокет открывается, и в консоли появляется сообщение.

_onopen

Затем я go в на вкладке сети в браузере и увидите ОГРОМНОЕ количество активно отправляемых запросов. Вот один из них.

Request URL: ws://localhost:10000/bg/javax.faces.push/someChannel?55685979-de8b-4a27-b497-f726cbea02ca
Request Method: GET
Status Code: 101

Connection: upgrade
Date: Tue, 16 Jun 2020 10:46:22 GMT
Sec-WebSocket-Accept: L4F6dcI3YMvkvsRhG7IyGCWYxuI=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Upgrade: websocket

Я предполагаю, что это из-за переподключения веб-сокета, который не может восстановить sh соединение. Я go в журнал сервера и действительно вижу, как это исключение повторяется снова и снова.

16-Jun-2020 13:15:54.153 SEVERE [http-nio-10000-exec-2] org.apache.coyote.AbstractProtocol$ConnectionHandler.process Error reading request, ignored
    java.lang.NullPointerException
        at com.sun.faces.cdi.CdiUtils.getBeanReferenceByType(CdiUtils.java:230)
        at com.sun.faces.cdi.CdiUtils.getBeanReference(CdiUtils.java:213)
        at com.sun.faces.push.WebsocketSessionManager.getInstance(WebsocketSessionManager.java:240)
        at com.sun.faces.push.WebsocketEndpoint.onOpen(WebsocketEndpoint.java:88)
        at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.init(WsHttpUpgradeHandler.java:133)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:856)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)

Я отлаживаю трассировку стека и недоумеваю над этим методом.

public static <T> T getBeanReference(Class<T> type, Annotation... qualifiers) {
    return type.cast(getBeanReferenceByType(Util.getCdiBeanManager(FacesContext.getCurrentInstance()), type, qualifiers));
}

где FacesContext.getCurrentInstance() возвращает null, преобразовывая диспетчер CDI в null, что вызывает исключение. Это вполне понятно, так как никакие артефакты JSF не затрагиваются на пути, что означает, что либо CDI настроен неправильно, либо я что-то упускаю. .

/**
 * Internal usage only. Awkward workaround for it being unavailable via @Inject in endpoint in Tomcat+Weld/OWB.
 */
static WebsocketSessionManager getInstance() {
    if (instance == null) {
        instance = getBeanReference(WebsocketSessionManager.class);
    }

    return instance;
}

Любой толчок действительно приветствуется. Спасибо.


Обновление:

Я заметил, что com.sun.faces.config.FacesInitializer ищет

org.glassfish.tyrus.servlet.TyrusServletContainerInitializer

в этом бите

    Class<?> tyrusInitializerClass;
    try {
        tyrusInitializerClass = cl.loadClass("org.glassfish.tyrus.servlet.TyrusServletContainerInitializer");
    } catch (ClassNotFoundException cnfe) {
        // No possibility of WebSocket.
        return;
    }

и я был интересно, нужна ли мне эта зависимость.


Обновление 2:

Я обнаружил эти проблемы, которые кажутся связанными:

...