问题
这个问题主要是因为websocket的工作方式导致的,下面是详细解决方案
解决
websocket 端点类通常不受 spring ioc 管理的原因在于它们是由 websocket 容器(例如,tomcat、jetty 等)而不是 spring 容器管理的。
websocket 规范(jsr 356)定义了 websocket 端点的生命周期和管理方式,这通常与 spring 的生命周期和依赖注入机制不同。
以下是一些具体原因和解决方法:
原因
不同的生命周期管理:
- websocket 端点的创建和管理是由 web 容器(如 tomcat、jetty 等)负责的,而不是由 spring 容器负责。
- 这意味着 websocket 端点类的实例化和生命周期管理不在 spring 的控制范围内。
注入机制不同:
- spring 的依赖注入机制依赖于 spring 容器管理的 bean,但 websocket 端点类实例化时,web 容器并不知道如何进行依赖注入。
解决方法
方法一:使用 spring boot 和 @configuration 配置
在 spring boot 项目中,可以通过配置类和自定义 websocket 处理器来管理 websocket 连接,这样可以使用 spring 容器管理的 bean。
创建 websocket 配置类:
import org.springframework.context.annotation.configuration; import org.springframework.web.socket.config.annotation.enablewebsocket; import org.springframework.web.socket.config.annotation.websocketconfigurer; import org.springframework.web.socket.config.annotation.websockethandlerregistry; @configuration @enablewebsocket public class websocketconfig implements websocketconfigurer { private final mywebsockethandler mywebsockethandler; public websocketconfig(mywebsockethandler mywebsockethandler) { this.mywebsockethandler = mywebsockethandler; } @override public void registerwebsockethandlers(websockethandlerregistry registry) { registry.addhandler(mywebsockethandler, "/websocket").setallowedorigins("*"); } }
创建 websocket 处理器类:
import org.springframework.web.socket.textmessage; import org.springframework.web.socket.websocketsession; import org.springframework.web.socket.handler.textwebsockethandler; import org.springframework.stereotype.component; @component public class mywebsockethandler extends textwebsockethandler { private final someservice someservice; public mywebsockethandler(someservice someservice) { this.someservice = someservice; } @override public void handletextmessage(websocketsession session, textmessage message) throws exception { string payload = message.getpayload(); system.out.println("消息为:" + payload); someservice.dosomething(); // 使用 spring bean session.sendmessage(new textmessage("servet 发送:" + payload)); } }
方法二:使用自定义 springconfigurator
创建自定义的 springconfigurator
:
import javax.websocket.server.serverendpointconfig; import org.springframework.web.context.contextloader; import org.springframework.web.context.webapplicationcontext; public class springconfigurator extends serverendpointconfig.configurator { @override public <t> t getendpointinstance(class<t> clazz) throws instantiationexception { webapplicationcontext context = contextloader.getcurrentwebapplicationcontext(); if (context == null) { throw new instantiationexception("unable to get spring context."); } return context.getautowirecapablebeanfactory().createbean(clazz); } }
在 @serverendpoint
注解中指定 configurator
:
import javax.websocket.onmessage; import javax.websocket.server.serverendpoint; import org.springframework.beans.factory.annotation.autowired; import org.springframework.stereotype.component; @serverendpoint(value = "/websocket", configurator = springconfigurator.class) @component public class mywebsocket { @autowired private someservice someservice; // 由 spring 管理的 bean @onmessage public string onmsg(string text) throws ioexception { system.out.println("消息为:" + text); someservice.dosomething(); // 使用 spring bean return "servet 发送:" + text; } }
方法三:手动获取 spring bean
创建 applicationcontextprovider 类:
import org.springframework.context.applicationcontext; import org.springframework.context.applicationcontextaware; import org.springframework.stereotype.component; @component public class applicationcontextprovider implements applicationcontextaware { private static applicationcontext context; @override public void setapplicationcontext(applicationcontext applicationcontext) { context = applicationcontext; } public static applicationcontext getapplicationcontext() { return context; } }
在 websocket 类中使用 applicationcontextprovider 获取 bean:
import javax.websocket.onmessage; import javax.websocket.server.serverendpoint; import org.springframework.stereotype.component; @serverendpoint(value = "/websocket") @component public class mywebsocket { private someservice someservice; public mywebsocket() { this.someservice = applicationcontextprovider.getapplicationcontext().getbean(someservice.class); } @onmessage public string onmsg(string text) throws ioexception { system.out.println("消息为:" + text); someservice.dosomething(); // 使用 spring bean return "servet 发送:" + text; } }
通过这些方法,你可以确保 websocket 端点类能够正确地访问由 spring ioc 管理的 bean,从而避免空指针异常。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论