基于web服务器的websocket
- pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 使用
-
- 注入ServerEndpointExporter
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
-
- 声明端口
@ServerEndpoint("/webim/{userid}")
@Slf4j
public class WebSocketEndpoint {
@OnOpen
public void open(@PathParam("userid") String userid, Session session){
}
@OnClose
public void close(@PathParam("userid") String userid, Session session){
log.info("on close : " + userid);
}
@OnError
public void error(@PathParam("userid") String userid, Session session, Throwable error){
log.info("on error : " + userid);
}
@OnMessage
public void handleMessage(@PathParam("userid") String userid, Session session, String message) throws IOException {
log.info(userid + " on message :" )
}
}
基于netty的websocket
- 推荐:https://gitee.com/Yeauty/netty-websocket-spring-boot-starter
代码解读
在spring.factories中定义了需要加载的配置项:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.yeauty.autoconfigure.NettyWebSocketAutoConfigure
在配置项中,使用了注解@EnableWebSocket,所以我们可以通过@EnableWebSocket来定义我们的websocket server
@EnableWebSocket
public class NettyWebSocketAutoConfigure {
}
EnableWebSocket通过Import的方式又加载了NettyWebSocketSelector,并且在里面创建了一个ServerEndpointExporter,这是整个服务的核心类。
ServerEndpointExporter主要做了以下工作:
- 完成了websocket服务地址和netty server实例的对应并且缓存。注意,整个实例是spring的代理类。
//ServerEndpointExporter.java
//可以创建多个websocket服务
private final Map<InetSocketAddress, WebsocketServer> addressWebsocketServerMap = new HashMap<>();
那么,addressWebsocketServerMap 又是怎么添加上的?
//继承ApplicationObjectSupport就可以通过getApplicationContext()取到上下文,从而取到对应的代理类
public class ServerEndpointExporter extends ApplicationObjectSupport implements SmartInitializingSingleton, BeanFactoryAware {
protected void registerEndpoints() {
// 通过ServerEndpoint取到SpringContext中的ServerEndpoint代理实例。
Set<Class<?>> endpointClasses = new LinkedHashSet<>();
ApplicationContext context = getApplicationContext();
if (context != null) {
String[] endpointBeanNames = context.getBeanNamesForAnnotation(ServerEndpoint.class);
for (String beanName : endpointBeanNames) {
endpointClasses.add(context.getType(beanName));
}
}
for (Class<?> endpointClass : endpointClasses) {
registerEndpoint(endpointClass);
}
//调用了WebsocketServer的init
init();
}
....
}
WebsocketServer在init方法中启动了netty server。并且添加了一个HttpServerHandler,在read方法中完成了消息的读取、发送、握手等操作。
HttpServerHandler.java
HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>
创建websocket需要注意的事项
- 安全性:只有系统用户可以连接,因此,在握手时需要校验身份。
- 重连机制