错误详情:
springboot + quartz + websocket (spring 自带得websocket 模块) 引起的冲突问题
contextLoads(com.kzcm.higo.HigoApplicationTests) Time elapsed: 0.033 s <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'defaultSockJsTaskScheduler' is expected to be of type 'org.springframework.scheduling.TaskScheduler' but was actually of type 'org.springframework.beans.factory.support.NullBean'
环境配置:
springboot + quartz 定时任务 + websocket (spring 自带得websocket 模块)
说明:
集成自网上下载得一个 layui 后台管理框架,当没用把 websocket 模块加入项目中得时候,项目可以正常启动,但是加入之后就报错,一直以为是 quartz 本身得问题,把quartz得sql 表重新执行了几次还是不能启动,后来用mvn 打包才报出最上面得错误,才定位到是websocket 模块得问题,下面得报错是springboot 得报错,根本无从找起
Exception in thread "Quartz Scheduler [MySiteForMeScheduler]" org.springframework.scheduling.SchedulingException: Could not start Quartz Scheduler after delay; nested exception is org.quartz.SchedulerException: The Scheduler cannot be restarted after shutdown() has been called.
at org.springframework.scheduling.quartz.SchedulerFactoryBean$1.run(SchedulerFactoryBean.java:753)
Caused by: org.quartz.SchedulerException: The Scheduler cannot be restarted after shutdown() has been called.
at org.quartz.core.QuartzScheduler.start(QuartzScheduler.java:529)
at org.quartz.impl.StdScheduler.start(StdScheduler.java:142)
at org.springframework.scheduling.quartz.SchedulerFactoryBean$1.run(SchedulerFactoryBean.java:750)
参考: https://www.cnblogs.com/threadj/articles/10631193.html
参考: https://blog.youkuaiyun.com/u013565163/article/details/80659828
参考: https://stackoverflow.com/questions/56169448/scheduled-task-not-working-with-websockets
问题定位:
最后全剧搜索 DefaultSockJsTaskScheduler ,通过搜索类得方式发现再
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>5.1.8.RELEASE</version>
<scope>compile</scope>
</dependency>
这个依赖中 org.springframework.web.socket.config.annotation.WebSocketConfigurationSupport 有一个生成定时器类的方法,最后一个方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.socket.config.annotation;
import org.springframework.context.annotation.Bean;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.Assert;
import org.springframework.web.servlet.HandlerMapping;
public class WebSocketConfigurationSupport {
@Nullable
private ServletWebSocketHandlerRegistry handlerRegistry;
@Nullable
private TaskScheduler scheduler;
public WebSocketConfigurationSupport() {
}
@Bean
public HandlerMapping webSocketHandlerMapping() {
ServletWebSocketHandlerRegistry registry = this.initHandlerRegistry();
if (registry.requiresTaskScheduler()) {
TaskScheduler scheduler = this.defaultSockJsTaskScheduler();
Assert.notNull(scheduler, "Expected default TaskScheduler bean");
registry.setTaskScheduler(scheduler);
}
return registry.getHandlerMapping();
}
private ServletWebSocketHandlerRegistry initHandlerRegistry() {
if (this.handlerRegistry == null) {
this.handlerRegistry = new ServletWebSocketHandlerRegistry();
this.registerWebSocketHandlers(this.handlerRegistry);
}
return this.handlerRegistry;
}
protected void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
}
@Bean
@Nullable
public TaskScheduler defaultSockJsTaskScheduler() {
if (this.initHandlerRegistry().requiresTaskScheduler()) {
ThreadPoolTaskScheduler threadPoolScheduler = new ThreadPoolTaskScheduler();
threadPoolScheduler.setThreadNamePrefix("SockJS-");
threadPoolScheduler.setPoolSize(Runtime.getRuntime().availableProcessors());
threadPoolScheduler.setRemoveOnCancelPolicy(true);
this.scheduler = threadPoolScheduler;
}
return this.scheduler;
}
}
解决:
在 quart的配置类中手动增加 对应的 引入@Bean
@Bean
@Nullable
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler threadPoolScheduler = new ThreadPoolTaskScheduler();
threadPoolScheduler.setThreadNamePrefix("SockJS-");
threadPoolScheduler.setPoolSize(Runtime.getRuntime().availableProcessors());
threadPoolScheduler.setRemoveOnCancelPolicy(true);
return threadPoolScheduler;
}