我有一个扩展TextWebSocketHandler
的类,其主要目的是在WebSocketSession
的某个事件之后向客户发送消息。为了实现这一点,我决定使用Spring AOP提供的方法拦截。
问题是当拦截器被调用时WebSocketSession
的封装实例变为null
,即使它在方法afterConnectionEstablished()
中实例化之前(可以通过调试器看到)。有趣的是,在类的每个其他方法中都可以访问会话实例。
以下是该类的代码:
@Aspect
public class SystemStateWS extends TextWebSocketHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(SystemStateWS.class);
private WebSocketSession session;
public SystemStateWS() {
}
@Override
public synchronized void afterConnectionEstablished(WebSocketSession session) throws Exception {
this.session = session;
}
@Override
protected synchronized void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
System.out.println(message.getPayload());
}
@Before("execution(* org.company.MyRestService.processTablesClearQuery(..))")
public void onConfigurationStart(JoinPoint joinPoint) {
if (session.isOpen()) { // session is null here
try {
session.sendMessage(new TextMessage("config started"));
LOGGER.debug("Configuration status message was sent to client");
} catch (IOException e) {
LOGGER.warn("Error during the passing of the message to client");
}
} else {
LOGGER.warn("Unable to send message to client: session is closed");
}
}
@Override
public synchronized void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
LOGGER.debug("Socket is closing");
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
super.handleTransportError(session, exception);
LOGGER.warn("Transport error", exception);
}
}
上下文配置文件:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket.xsd">
<context:component-scan base-package="org.company" />
<aop:aspectj-autoproxy/>
...
<websocket:handlers>
<websocket:mapping path="/ws/sysState" handler="sysStateHandler" />
<websocket:handshake-handler ref="handshakeHandler"/>
</websocket:handlers>
<bean class="org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean">
<property name="maxTextMessageBufferSize" value="335544"/>
<property name="maxBinaryMessageBufferSize" value="335544"/>
</bean>
<bean id="handshakeHandler" class="org.springframework.web.socket.server.support.DefaultHandshakeHandler">
<constructor-arg ref="upgradeStrategy"/>
</bean>
<bean id="upgradeStrategy" class="org.springframework.web.socket.server.standard.TomcatRequestUpgradeStrategy">
</bean>
<bean id="sysStateHandler" class="org.springframework.web.socket.handler.PerConnectionWebSocketHandler">
<constructor-arg type="java.lang.Class" value="org.company.SystemStateWS"/>
</bean>
<bean id="systemStateWS" class="org.company.SystemStateWS"/>
</beans>
MyRestService.processTablesClearQuery
中引用的 @Before
实际上是应用程序的一个REST控制器中的方法,但我认为这里并不重要。
不幸的是,我对这些方面并不熟悉。首先,我甚至不知道是否可以将套接字处理程序与@Aspect
组合在一起。如果可能的话WebSocketSession
成为null
的原因是什么,我怎么可能避免它?任何帮助表示赞赏。
答案 0 :(得分:0)
所以这种行为的实际原因是在触发拦截器的那一刻,许多SystemStateWS
实例的存在。拦截器刚刚在从未调用方法afterConnectionEstablished()
的实例中触发,因此WebSocketSession
的引用继续保留null
。
因此,每当在一个特殊bean中调用方法afterConnectionEstablished()
,然后为拦截器创建独立类时,我就决定注册我的Web套接字类的每个实例。当它现在被调用时,它只是在所有已注册的Web套接字实例中调用必要的方法。这段代码对我有用:
在缓冲区中注册套接字类:
@Autowired
private SystemStateWebSocketBuffer buffer;
//...
@Override
public synchronized void afterConnectionEstablished(WebSocketSession session)
throws Exception {
this.session = session;
buffer.add(this);
}
<强> SystemStateWebSocketBuffer.java 强>
@Component
public class SystemStateWebSocketBuffer {
private List<SystemStateWS> systemStateSockets = new ArrayList<>();
public void add(SystemStateWS systemStateWS) {
this.systemStateSockets.add(systemStateWS);
}
public List<SystemStateWS> getSystemStateSockets() {
return systemStateSockets;
}
public void setSystemStateSockets(List<SystemStateWS> systemStateSockets) {
this.systemStateSockets = systemStateSockets;
}
}
<强> SystemStateRestInterceptor.java 强>
@Aspect
public class SystemStateRestInterceptor {
@Autowired
private SystemStateWebSocketBuffer systemStateWebSocketBuffer;
@Before("execution(* org.company.MyRestService.processTablesClearQuery(..))")
public void interceptConfigStartEvent() {
systemStateWebSocketBuffer.getSystemStateSockets()
.forEach(socket -> socket.onConfigurationStart());
}
}