来源在 Spring Boot 中整合、使用 WebSocket - spring 中文网
服务可以正常启动,看似一切都没问题!可是当你在事件方法中使用这 Bean 的时候就会导致 NullPointerException 异常。
原因:运行时的 WebSocket 连接对象,也就是端点实例,是由 服务器创建,而不是 Spring,所以不能使用自动装配。上文也提到过 “服务器会为每个连接创建一个端点实例对象”。
知道了原因后,解决办法也很简单,我们可以使用 Spring 的 ApplicationContextAware 接口,在应用启动时获取到 ApplicationContext 并且保存在全局静态变量中。
服务器每次创建连接的时候,我们就在 @OnOpen 事件方法中从 ApplicationContext 获取到需要 Bean 来初始化端点对象。
private static ApplicationContext applicationContext; 的声明通常用于存储 Spring 应用上下文的实例,以便在静态方法中访问 Spring 管理的 Bean。它的主要作用和用途包括:
主要作用
-
全局访问:
- 通过静态方法访问 Spring 容器中的 Bean。这样,你可以在任何地方(即使在非 Spring 管理的类中)获取 Spring Bean 的实例。
-
避免手动注入:
- 如果某个类不是 Spring 管理的 Bean,你可以通过
applicationContext直接获取其他 Bean,而无需进行显式的依赖注入。
- 如果某个类不是 Spring 管理的 Bean,你可以通过
关键代码 EchoChannel.applicationContext.getBean(你想导入的类.class)
@ServerEndpoint(value = "/channel/echo")
@Component // 由 spring 扫描管理
public class EchoChannel implements
ApplicationContextAware { // 实现 ApplicationContextAware 接口, Spring 会在运行时注入 ApplicationContext
private static final Logger LOGGER = LoggerFactory.getLogger(EchoChannel.class);
// 全局静态变量,保存 ApplicationContext
private static ApplicationContext applicationContext;
private Session session;
// 声明需要的 Bean
private UserService userService;
// 保存 Spring 注入的 ApplicationContext 到静态变量
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
EchoChannel.applicationContext = applicationContext;
}
@OnOpen
public void onOpen(Session session, EndpointConfig endpointConfig){
// 保存 session 到对象
this.session = session;
// 连接创建的时候,从 ApplicationContext 获取到 Bean 进行初始化
this.userService = EchoChannel.applicationContext.getBean(UserService.class);
// 在业务中使用
this.userService.foo();
LOGGER.info("[websocket] 新的连接:id={}", this.session.getId());
}
// ....
}

被折叠的 条评论
为什么被折叠?



