У меня простой 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:
Я обнаружил эти проблемы, которые кажутся связанными: