SpringBoot webSocket 资源无法加载、tomcat启动报错解决方法

问题描述:

1. 项目集成WebSocket,且打包发布tomcat时出现websocket is already in CLOSING or CLOSE state这样的问题,建议参考“解决方法二”,但是“解决方法一”请要了解查看 ,因为解决方法二是在一的基础上进行更正

2. 如果出现javax.websocket.server.ServerContainer not available这样的错误,请参考“解决方法一”中步骤3

 

解决方法一:(常规解决、不推荐)

步骤1:在BootApplication中修改:

public static void main(String[] args) {
		SpringApplication springApplication = new SpringApplication(BootApplication.class);
		springApplication.addListeners(new ApplicationPidFileWriter());
		ConfigurableApplicationContext applicationContext = springApplication.run(args);
		WebSocketServer.setApplicationContext(applicationContext);
	}

注:这里的WebSocketServer是指你自定义的websocket接受消息的服务类

 

步骤2:修改WebSocketServer

    private static ManageUserMapper manageUserMapper;

    public static void setApplicationContext(ConfigurableApplicationContext         applicationContext) {
        WebSocketServer.manageUserMapper = applicationContext.getBean(ManageUserMapper.class);
    }

 

步骤3: 修改pom.xml

由于我们在开发过程中,如果按照以上步骤1、2进行修改,一般不会出现问题,

但是如果我们打包发布tomcat,就会出现:javax.websocket.server.ServerContainer not available这样的错误,步骤3为常规解决一下问题方式

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<!-- 去除内嵌tomcat -->
			<exclusions>
				 <exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-tomcat</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

需要去除web-starter的tomcat,因为如果不去除会导致冲突,

如果出现这种问题,你还需要在websocketConfig中做如下修改:(websocket为自定义配置类)

 /**
     * 服务器节点
     *
     * 如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理
     * @return
     */
    @Bean
    @Profile("dev")
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

在application.properties做如下配置

##prod:生产环境  dev:开发环境(WINDOWS)
spring.profiles.active=dev

这里加入了@Profile("dev") 这个注解。意思是在开发的过程中去调用

.记住如果开发过程中,记得一定要把pom.xml中的去除tomcat那句话给注释掉,上线才需要去除

 

问题反思:(为什么不建议这么解决问题)

这种方式确实可以常规解决websocket打包tomcat不报错问题,同时也解决了在资源无法加载的问题,但是这样却十分的麻烦,理由如下:

1. 繁琐:生产环境和开发环境要一直切换是否注释tomcat

2. 局限性大:我们在BootApplication中添加了websocketserver去访问资源的语句,但是其他地方难道没有需要调用的吗,如果有,难道像这样一直累计添加下去,每个server设置一下

核心思想是资源无法加载的问题,如果你有写线程,且线程你也调用了数据库资源,那么解决方法是一致,编写一个公用的工具类解决

 

解决方法二:(推荐)

步骤1:新建一个工具类,getbeanTool

此工具类为之后加载资源的工具类,公用

@Component
public class GetBeanTool implements ApplicationContextAware{
	
	private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        GetBeanTool.applicationContext = applicationContext;
    }

    public static Object getBeanByName(String beanName) {
        if (applicationContext == null){
            return null;
        }
        return applicationContext.getBean(beanName);
    }

    public static <T> T getBean(Class<T> type) {
        return applicationContext.getBean(type);
    }

}

步骤2:在线程、websocket等server中,加载资源

以WebSocketServer作为参考,如下修改:


    private  ManageUserMapper manageUserMapper;
    
    public WebSocketServer() {
    	this.manageUserMapper=GetBeanTool.getBean(ManageUserMapper.class);
    }

这么做你就不用在BootApplication中添加语句,来让你的server去调用资源了,一步到位,大家都能用,需要的时候直接通过getbeanTool去请求就行了

 

步骤3:解决tomcat开发环境,生产环境pom.xml中注释和打开内置tomcat的问题

这里需要修改BootApplication,如下修改:

@SpringBootApplication
@Configuration
public class BootApplication extends SpringBootServletInitializer {

	@Override
	protected SpringApplicationBuilder configure(
			SpringApplicationBuilder application) {
		return application.sources(BootApplication.class);
	}


	public static void main(String[] args) {
		SpringApplication.run(BootApplication.class, args);
	}
}

可以看到这里我继承了SpringBootServletInitializer ,同时重写了configure方法。采用这种写法,如论是开发还是测试,你都不用管是否需要注释内置的tomcat了,是不是很方便,至于原理,这里不解释,篇幅太长,自己去百度吧

 

总结:

1. 最近做了一个简单的IM功能,遇到了这些问题,作为记录,防止哪天我忘了

2. 网上解决方法的可能有用,但是写的不明不白,不友好,而且不见得好用,在解决问题的时候一定要考虑到通用性,开发一定要为了便利,不然坑了你也坑了被人,改这改那谁尼玛记得住

3. 此博文为本人自身角度进行编写,作为记录。如对他人有帮助,可以点个赞,本人不回复,不评论。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了释放WebSocket资源,我们需要在WebSocket连接关闭时执行一些操作。Spring Boot提供了一个WebSocketHandlerDecoratorFactory,可以用来装饰WebSocketHandler并添加一些处理程序。我们可以使用这个工厂来添加一个处理程序,以在WebSocket连接关闭时释放资源。 以下是一个示例代码,演示如何使用WebSocketHandlerDecoratorFactory释放WebSocket资源: ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myHandler(), "/myHandler") .addInterceptors(new HttpSessionHandshakeInterceptor()); } @Bean public WebSocketHandler myHandler() { return new MyHandler(); } @Bean public WebSocketHandlerDecoratorFactory webSocketHandlerDecoratorFactory() { return new WebSocketHandlerDecoratorFactory() { @Override public WebSocketHandler decorate(WebSocketHandler handler) { return new WebSocketHandlerDecorator(handler) { @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { // 在连接关闭时释放资源 // 释放代码 super.afterConnectionClosed(session, closeStatus); } }; } }; } } ``` 在上面的代码中,我们创建了一个WebSocketHandlerDecoratorFactory bean,并覆盖了decorate方法。在decorate方法中,我们创建了一个WebSocketHandlerDecorator,覆盖了afterConnectionClosed方法。在afterConnectionClosed方法中,我们可以释放WebSocket资源

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值