netty websocket spring boot starter

:rocket: lightweight high-performance WebSocket framework ( 轻量级、高性能的WebSocket框架)

1827
540
Java

netty-websocket-spring-boot-starter License

中文文档 (Chinese Docs)

About

netty-websocket-spring-boot-starter will help you develop WebSocket server by using Netty in spring-boot,it is easy to develop by using annotation like spring-websocket

Requirement

  • jdk version 1.8 or 1.8+

Quick Start

  • add Dependencies:
	<dependency>
		<groupId>org.yeauty</groupId>
		<artifactId>netty-websocket-spring-boot-starter</artifactId>
		<version>0.12.0</version>
	</dependency>
  • annotate @ServerEndpoint on endpoint class,and annotate @BeforeHandshake,@OnOpen,@OnClose,@OnError,@OnMessage,@OnBinary,@OnEvent on the method. e.g.
@ServerEndpoint(path = "/ws/{arg}")
public class MyWebSocket {

    @BeforeHandshake
    public void handshake(Session session, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap){
        session.setSubprotocols("stomp");
        if (!"ok".equals(req)){
            System.out.println("Authentication failed!");
            session.close();
        }
    }
    
    @OnOpen
    public void onOpen(Session session, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap){
        System.out.println("new connection");
        System.out.println(req);
    }

    @OnClose
    public void onClose(Session session) throws IOException {
       System.out.println("one connection closed"); 
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        throwable.printStackTrace();
    }

    @OnMessage
    public void onMessage(Session session, String message) {
        System.out.println(message);
        session.sendText("Hello Netty!");
    }

    @OnBinary
    public void onBinary(Session session, byte[] bytes) {
        for (byte b : bytes) {
            System.out.println(b);
        }
        session.sendBinary(bytes); 
    }

    @OnEvent
    public void onEvent(Session session, Object evt) {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            switch (idleStateEvent.state()) {
                case READER_IDLE:
                    System.out.println("read idle");
                    break;
                case WRITER_IDLE:
                    System.out.println("write idle");
                    break;
                case ALL_IDLE:
                    System.out.println("all idle");
                    break;
                default:
                    break;
            }
        }
    }

}
  • use Websocket client to connect ws://127.0.0.1:80/ws/xxx

Annotation

@ServerEndpoint

declaring ServerEndpointExporter in Spring configuration,it will scan for WebSocket endpoints that be annotated with ServerEndpoint .
beans that be annotated with ServerEndpoint will be registered as a WebSocket endpoint.
all configurations are inside this annotation ( e.g. @ServerEndpoint("/ws") )

@BeforeHandshake

when there is a connection accepted,the method annotated with @BeforeHandshake will be called
classes which be injected to the method are:Session,HttpHeaders…

@OnOpen

when there is a WebSocket connection completed,the method annotated with @OnOpen will be called
classes which be injected to the method are:Session,HttpHeaders…

@OnClose

when a WebSocket connection closed,the method annotated with @OnClose will be called
classes which be injected to the method are:Session

@OnError

when a WebSocket connection throw Throwable, the method annotated with @OnError will be called
classes which be injected to the method are:Session,Throwable

@OnMessage

when a WebSocket connection received a message,the method annotated with @OnMessage will be called
classes which be injected to the method are:Session,String

@OnBinary

when a WebSocket connection received the binary,the method annotated with @OnBinary will be called
classes which be injected to the method are:Session,byte[]

@OnEvent

when a WebSocket connection received the event of Netty,the method annotated with @OnEvent will be called
classes which be injected to the method are:Session,Object

Configuration

all configurations are configured in @ServerEndpoint’s property

property default description
path “/” path of WebSocket can be aliased for value
host “0.0.0.0” host of WebSocket."0.0.0.0" means all of local addresses
port 80 port of WebSocket。if the port equals to 0,it will use a random and available port(to get the port Multi-Endpoint)
bossLoopGroupThreads 0 num of threads in bossEventLoopGroup
workerLoopGroupThreads 0 num of threads in workerEventLoopGroup
useCompressionHandler false whether add WebSocketServerCompressionHandler to pipeline
optionConnectTimeoutMillis 30000 the same as ChannelOption.CONNECT_TIMEOUT_MILLIS in Netty
optionSoBacklog 128 the same as ChannelOption.SO_BACKLOG in Netty
childOptionWriteSpinCount 16 the same as ChannelOption.WRITE_SPIN_COUNT in Netty
childOptionWriteBufferHighWaterMark 64*1024 the same as ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK in Netty,but use ChannelOption.WRITE_BUFFER_WATER_MARK in fact.
childOptionWriteBufferLowWaterMark 32*1024 the same as ChannelOption.WRITE_BUFFER_LOW_WATER_MARK in Netty,but use ChannelOption.WRITE_BUFFER_WATER_MARK in fact.
childOptionSoRcvbuf -1(mean not set) the same as ChannelOption.SO_RCVBUF in Netty
childOptionSoSndbuf -1(mean not set) the same as ChannelOption.SO_SNDBUF in Netty
childOptionTcpNodelay true the same as ChannelOption.TCP_NODELAY in Netty
childOptionSoKeepalive false the same as ChannelOption.SO_KEEPALIVE in Netty
childOptionSoLinger -1 the same as ChannelOption.SO_LINGER in Netty
childOptionAllowHalfClosure false the same as ChannelOption.ALLOW_HALF_CLOSURE in Netty
readerIdleTimeSeconds 0 the same as readerIdleTimeSeconds in IdleStateHandler and add IdleStateHandler to pipeline when it is not 0
writerIdleTimeSeconds 0 the same as writerIdleTimeSeconds in IdleStateHandler and add IdleStateHandler to pipeline when it is not 0
allIdleTimeSeconds 0 the same as allIdleTimeSeconds in IdleStateHandler and add IdleStateHandler to pipeline when it is not 0
maxFramePayloadLength 65536 Maximum allowable frame payload length.
useEventExecutorGroup true Whether to use another thread pool to perform time-consuming synchronous business logic
eventExecutorGroupThreads 16 num of threads in bossEventLoopGroup
sslKeyPassword “”(mean not set) the same as server.ssl.key-password in spring-boot
sslKeyStore “”(mean not set) the same as server.ssl.key-store in spring-boot
sslKeyStorePassword “”(mean not set) the same as server.ssl.key-store-password in spring-boot
sslKeyStoreType “”(mean not set) the same as server.ssl.key-store-type in spring-boot
sslTrustStore “”(mean not set) the same as server.ssl.trust-store in spring-boot
sslTrustStorePassword “”(mean not set) the same as server.ssl.trust-store-password in spring-boot
sslTrustStoreType “”(mean not set) the same as server.ssl.trust-store-type in spring-boot
corsOrigins {}(mean not set) the same as @CrossOrigin#origins in spring-boot
corsAllowCredentials “”(mean not set) the same as @CrossOrigin#allowCredentials in spring-boot

Configuration by application.properties

You can get the configurate of application.properties by using ${...} placeholders. for example:

  • first,use ${...} in @ServerEndpoint
@ServerEndpoint(host = "${ws.host}",port = "${ws.port}")
public class MyWebSocket {
    ...
}
  • then configurate in application.properties
ws.host=0.0.0.0
ws.port=80

Custom Favicon

The way of configure favicon is the same as spring-boot.If favicon.ico is presented in the root of the classpath,it will be automatically used as the favicon of the application.the example is following:

src/
  +- main/
      +- java/
      |   + <source code>
      +- resources/
          +- favicon.ico

Custom Error Pages

The way of configure favicon is the same as spring-boot.you can add a file to an /public/error
folder.The name of the error page should be the exact status code or a series mask.the example is following:

src/
  +- main/
      +- java/
      |   + <source code>
      +- resources/
          +- public/
              +- error/
              |   +- 404.html
              |   +- 5xx.html
              +- <other public assets>

Multi Endpoint

  • base on Quick-Start,use annotation @ServerEndpoint and @Component in classes which hope to become a endpoint.
  • you can get all socket addresses in ServerEndpointExporter.getInetSocketAddressSet().
  • when there are different addresses(different host or different port) in WebSocket,they will use different ServerBootstrap instance.
  • when the addresses are the same,but path is different,they will use the same ServerBootstrap instance.
  • when multiple port of endpoint is 0 ,they will use the same random port
  • when multiple port of endpoint is the same as the path,host can’t be set as “0.0.0.0”,because it means it binds all of the addresses

Change Log

0.8.0

  • Auto-Configuration

0.9.0

  • Support RESTful by @PathVariable
  • Get param by@RequestParam from query
  • Remove ParameterMap ,instead of @RequestParam MultiValueMap
  • Add @BeforeHandshake annotation,you can close the connect before handshake
  • Set sub-protocol in @BeforeHandshake event
  • Remove the @Component on endpoint class
  • Update Netty version to 4.1.44.Final

0.9.1

  • Bug fixed : it was null when using @RequestParam MultiValueMap to get value
  • Update Netty version to 4.1.45.Final

0.9.2

  • There are compatibility version under 0.8.0 that can configure the ServerEndpointExporter manully

0.9.3

  • Bug fixed :when there is no @BeforeHandshake , NullPointerException will appear

0.9.4

  • Bug fixed :when there is no @BeforeHandshake , Session in OnOpen is null

0.9.5

  • Bug fixed :Throwable in OnError event is null

0.10.0

  • Modified the default value of bossLoopGroupThreads to 1
  • Supports configuring useEventExecutorGroup to run synchronous and time-consuming business logic in EventExecutorGroup, so that the I/O thread is not blocked by a time-consuming task
  • SSL supported
  • CORS supported
  • Update Netty version to 4.1.49.Final

0.11.0

  • When the ServerEndpoint class is proxied by CGLIB (as with AOP enhancement), it still works

0.12.0

  • @enableWebSocket adds the scanBasePackages attribute
  • @serverEndpoint no longer depends on @Component
  • Update Netty version to 4.1.67.Final