錯誤詳情:
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.csdn.net/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;
}