问题
这个问题主要是因为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,从而避免空指针异常。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论