版权声明:本文为博主原屙文章,喜欢你就担走。 https://blog.csdn.net/leftfist/article/details/89217214
唉,真拗口啊这标题,也不知道说的对不对,好像很不专业的说法?大致是这么个意思吧。
总所周知,spring boot最喜欢最擅长干的事情就是标注。多复杂的事情,只要加个标注就好了。1个不够,就加2个。没有标注解决不了的问题。
比如说,类的实例化,只需加个 @Autowired
就好了:
@Autowired SocketService skService;
但是!在websocket 服务器端代码中,这种实例会失效,根本没有构造实例,skService为null。
为什么会这样呢?
原因据说是spring 为单例模式,而websocket是多对象,每个会话会创建一个websocket对象。导致除了第一个websocket,其他的都不能注入实例。
本质原因:spring管理的都是单例(singleton),和 websocket (多对象)相冲突。
原文: https://blog.csdn.net/m0_37202351/article/details/86255132
我寻寻觅觅,找到的答案都说是要在每个具体的上下文里自己构造实例。试验之后,果真如此,代码如下:
websocket服务端
import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; @ServerEndpoint("/ws") @Component public class CaptureSocket { private final static Logger LOGGER = LoggerFactory.getLogger(CaptureSocket.class); private static CopyOnWriteArraySet<CaptureSocket> set = new CopyOnWriteArraySet<>(); private Session session; //关键代码,设置一个静态上下文属性appcontext private static ApplicationContext appcontext; public static void setAppcontext(ApplicationContext appcontext) { CaptureSocket.appcontext = appcontext; } public static ApplicationContext getAppcontext() { return appcontext; } @OnMessage public void onMessage(String message,Session session){ LOGGER.info("来自客户端消息:" + message); //手动构造实例 //这个构造实例,要放在事件里进行,如果放在代码开头,极有可能失败,可能是还没来得及拿到这个上下文对象? SocketService skService = appcontext.getBean(SocketServiceImpl.class); } @OnOpen public void onOpen(Session session) throws IOException,InterruptedException { this.session=session; set.add(this); LOGGER.info("新连接来自:" + session.getRequestURI().getHost()); } @OnClose public void onClose(){ set.remove(this); LOGGER.info("连接关闭:" + this.session.getRequestURI().getHost()); } @OnError public void onError(Session session,Throwable err){ LOGGER.info(err.getMessage()); err.printStackTrace(); } }
在主程序入口里,将上下文对象保存下来,保存到websocket代码设置的静态属性appcontext里。如此,即可用该上下文对象来构造实例矣。
@SpringBootApplication @EnableAsync public class OptcFfmpegApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(OptcFfmpegApplication.class, args); CaptureSocket.setAppcontext(context); } }
但是要注意,这个构造实例,要放在事件里进行,如果放在代码开头,极有可能失败,可能是还没来得及拿到这个上下文对象?