Spring Cloud/Boot WebSocket 无法注入其他类的解决办法

SpringBoot官方文档推荐实现的WebSocket的方式是添加@ServerEndpoint这个注解。我也是按照推荐实现的。
但是有问题。
我开始的写的WebSocket的例子:

@ServerEndpoint(value = "/websocket" )
@Component
public class MyWebSocket
{   
    // 与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;

    @Autowired
    TestInfo testInfo;

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session)
    {
        System.out.println(this.hashCode());
        this.session = session;     
        try
        {
            System.out.println(testInfo.name);
            sendMessage("新用户添加进来了....");
        }
        catch (IOException e)
        {
            System.out.println("IO异常");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose()
    {       
        System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     *            客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session)
    {
        System.out.println("来自客户端的消息:" + message);
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error)
    {
        System.out.println("发生错误");
        error.printStackTrace();
    }

    public void sendMessage(String message) throws IOException
    {
        this.session.getBasicRemote().sendText(message);        
    }
}

当客户端发送请求的时候,会报空指针异常,TestInfo 为空。
创建MyWebSocket,也是通过@Bean的形式实现的。其他的地方都没有问题。

我已经autowired了,干嘛没注入啊。

TestInfo是通过Spring容器进行管理的,但是使用ServerEndpoint这个注解的时候,失效了
猜测原因就是这个MyWebSocket这个并不是Spring容器管理的。但是这个是官方推荐的实现方法 啊。

寻寻觅觅,最后在强大的stackoverflow中找到了解决问题的办法。
https://stackoverflow.com/questions/30483094/springboot-serverendpoint-failed-to-find-the-root-webapplicationcontext

第一种方法:

继续用ServerEndpoint。
定义一个MyEndpointConfigure

/**
 * 
 * @author lipengbin
 *
 */
public class MyEndpointConfigure extends ServerEndpointConfig.Configurator implements ApplicationContextAware
{
    private static volatile BeanFactory context;

    @Override
    public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException
    {
         return context.getBean(clazz);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
    {
        System.out.println("auto load"+this.hashCode());
        MyEndpointConfigure.context = applicationContext;
    }
}

这个类的核心就是getEndpointInstance(Class clazz)这个方法。
定义了获取类实例是通过ApplicationContext获取。

@Configuration
public class MyConfigure
{

    @Bean
    public MyEndpointConfigure newConfigure()
    {
        return new MyEndpointConfigure();
    }
}

修改MyWebSocket的注解

@ServerEndpoint(value = “/websocket” )

@ServerEndpoint(value = “/websocket”,configurator=MyEndpointConfigure.class)
大致的意思可以理解了,创建类需要通过MyEndpointConfigure.getEndpointInstance()这个来实现。

运行一切正常。
但是这种形式并不是正常的Spring容器去正常去管理这个WebSocket,个人觉得并不是很好。

这个帖子同时还给出了第二解决方法。原生的Spring实现的WebSocket的办法。

第二种解决办法:

与其说是第二种办法,不如说是Spring第二种实现WebSocket的方案。和第一种没有任何的联系。
代码如下:

核心Handler,有Spring的风格。

@Component
public class WsHandler extends TextWebSocketHandler
{

    @Autowired  
    TestInfo testInfo;

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception
    {
        super.afterConnectionClosed(session, status);
        System.out.println("close....");
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception
    {
        super.afterConnectionEstablished(session);
        System.out.println("----->"+testInfo.test());
        System.out.println("建立新的会话");
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception
    {       
        System.out.println(message.getPayload());
        TextMessage msg=new TextMessage(message.getPayload());
        session.sendMessage(msg);

    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception
    {
        super.handleMessage(session, message);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception
    {
        super.handleTransportError(session, exception);
    }

}

简单实现几个关键的方法。

TestInfo 直接注入。

编写Configure类

@Configuration
@EnableWebSocket
public class WsConfigure implements WebSocketConfigurer
{
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry)
    {
        System.out.println("==========================");
        registry.addHandler(myHandler(), "/websocket").setAllowedOrigins("*");
    }

    @Bean
    public WsHandler myHandler()
    {
        return new WsHandler();
    }
}

这种实现方法可以查看官方文档。
https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#websocket

经测试可以正常工作。
个人建议采用第二种方法,因为这个是Spring自带的WebSocket的实现方式。

实现上需要花时间看看Spring是如何将WebSocket的请求进行处理。以后有时间补上这个。

  • 15
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
以下是一个简单的Spring Cloud Gateway配置WebSocket的例子: 1. 添加依赖 在pom.xml文件添加以下依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 配置Gateway 在application.yml文件添加以下配置: ```yaml spring: cloud: gateway: routes: - id: ws_route uri: ws://localhost:8081 predicates: - Path=/websocket/** filters: - WebSocket ``` 这个配置将会将所有以`/websocket`开头的请求路由到`ws://localhost:8081`。 3. 配置WebSocket处理器 创建一个WebSocket处理器: ```java @Component public class MyWebSocketHandler extends TextWebSocketHandler { @Override public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException { // 处理消息 session.sendMessage(new TextMessage("Received: " + message.getPayload())); } } ``` 4. 配置WebSocketHandlerAdapter 创建一个WebSocketHandlerAdapter,用于将WebSocket处理器集成到Spring MVC: ```java @Configuration public class WebSocketConfig { @Bean public WebSocketHandlerAdapter handlerAdapter() { return new WebSocketHandlerAdapter(); } } ``` 5. 启动WebSocket服务器 创建一个WebSocket服务器: ```java @Configuration @EnableWebSocket public class WebSocketServerConfig implements WebSocketConfigurer { @Autowired private MyWebSocketHandler myWebSocketHandler; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myWebSocketHandler, "/websocket"); } } ``` 在启动添加@EnableWebSocketServer注解: ```java @SpringBootApplication @EnableWebSocketServer public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } } ``` 6. 测试WebSocket 使用WebSocket客户端连接到`ws://localhost:8080/websocket`,并发送一条消息,应该能够收到处理后的消息。 以上就是配置Spring Cloud Gateway支持WebSocket的简单例子。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值