计划任务不适用于 websockets
Scheduled task not working with websockets
我有一个 spring 带有 websockets 的引导应用程序:
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
@EnableScheduling
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
WebSocket 配置:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(socketHandler(), "/connect/*")
.setAllowedOrigins("*")
.addInterceptors(handshakeInterceptor());
}
@Bean
public WebSocketHandler socketHandler() {
return new CustomHandler();
}
@Bean
public HandshakeInterceptor handshakeInterceptor() {
return new CustomInterceptor();
}
}
它运行良好。
然后我添加了 @EnableSheduled
并创建了调度组件:
@Component
public class ScheduledTask {
@Scheduled(fixedRate = 1000)
public void printHello() {
System.out.println("hello");
}
}
并得到异常:
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'
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:392) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:224) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1116) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1083) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.resolveSchedulerBean(ScheduledAnnotationBeanPostProcessor.java:313) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:254) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:231) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:103) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:163) ~[spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at ru.test.project.TestApplication.main(TestApplication.java:17) [classes/:na]
我试图从我的项目中删除 websockets。在此之后,一切都开始正常工作。
如何解决?
这可以通过手动定义一个 TaskScheduler
bean 来解决,例如参见这个 post:https://medium.com/@jing.xue/spring-boot-application-startup-error-with-websocket-enabled-832456bb2e
因此,在 Java 术语中,这将是
@Bean
public TaskScheduler taskScheduler() {
TaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(2);
scheduler.setThreadNamePrefix("scheduled-task-");
scheduler.setDaemon(true);
return scheduler;
}
有更方便的方法可以解决这个问题。
您可以使用 @Configurable 和 @EnableScheduling 注释自定义调度程序 class 并实施 SchedulingConfigurer里面的界面。
然后你应该实现 configureTasks 方法,它有一个 ScheduledTaskRegistrar 对象作为它的输入参数。
使用此对象,您可以定义和执行任何类型的计划任务。
请记住,您需要在父 Bean 中就此通知 Spring 框架上下文。
父 Bean class 的构造函数:
public ParentBean() {
new AnnotationConfigApplicationContext(MyTaskScheduler.class);
}
MyTaskScheduler class :
@Configurable
@EnableScheduling
public class MyTaskScheduler implements SchedulingConfigurer {
@Override
public void configureTasks (ScheduledTaskRegistrar taskRegistrar) {
// -- Schedule task #1 --
taskRegistrar.addFixedDelayTask(() -> { firstTask(); }, 10000);
// -- Schedule task #2 --
taskRegistrar.addFixedRateTask(() -> { secondTask(); }, 1000);
}
private void firstTask() {
// -- Your first task logic goes here! --
}
private void secondTask() {
// -- Your second task logic goes here! --
}
}
除了米歇尔接受的答案:
使用Spring引导时,与其直接创建TaskScheduler,不如为其使用构建器更明智:
@Bean
public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
return builder.build();
}
生成器在 org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
中定义。因此,使用这种方法,您将获得与未使用 @EnableWebSocket 完全相同的调度程序(即,它将使用来自 spring 配置属性等的池大小)。
我有一个 spring 带有 websockets 的引导应用程序:
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
@EnableScheduling
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
WebSocket 配置:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(socketHandler(), "/connect/*")
.setAllowedOrigins("*")
.addInterceptors(handshakeInterceptor());
}
@Bean
public WebSocketHandler socketHandler() {
return new CustomHandler();
}
@Bean
public HandshakeInterceptor handshakeInterceptor() {
return new CustomInterceptor();
}
}
它运行良好。
然后我添加了 @EnableSheduled
并创建了调度组件:
@Component
public class ScheduledTask {
@Scheduled(fixedRate = 1000)
public void printHello() {
System.out.println("hello");
}
}
并得到异常:
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'
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:392) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:224) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1116) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1083) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.resolveSchedulerBean(ScheduledAnnotationBeanPostProcessor.java:313) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:254) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:231) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:103) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:163) ~[spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.5.BUILD-20190515.065035-40.jar:2.1.5.BUILD-SNAPSHOT]
at ru.test.project.TestApplication.main(TestApplication.java:17) [classes/:na]
我试图从我的项目中删除 websockets。在此之后,一切都开始正常工作。 如何解决?
这可以通过手动定义一个 TaskScheduler
bean 来解决,例如参见这个 post:https://medium.com/@jing.xue/spring-boot-application-startup-error-with-websocket-enabled-832456bb2e
因此,在 Java 术语中,这将是
@Bean
public TaskScheduler taskScheduler() {
TaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(2);
scheduler.setThreadNamePrefix("scheduled-task-");
scheduler.setDaemon(true);
return scheduler;
}
有更方便的方法可以解决这个问题。 您可以使用 @Configurable 和 @EnableScheduling 注释自定义调度程序 class 并实施 SchedulingConfigurer里面的界面。 然后你应该实现 configureTasks 方法,它有一个 ScheduledTaskRegistrar 对象作为它的输入参数。 使用此对象,您可以定义和执行任何类型的计划任务。 请记住,您需要在父 Bean 中就此通知 Spring 框架上下文。
父 Bean class 的构造函数:
public ParentBean() {
new AnnotationConfigApplicationContext(MyTaskScheduler.class);
}
MyTaskScheduler class :
@Configurable
@EnableScheduling
public class MyTaskScheduler implements SchedulingConfigurer {
@Override
public void configureTasks (ScheduledTaskRegistrar taskRegistrar) {
// -- Schedule task #1 --
taskRegistrar.addFixedDelayTask(() -> { firstTask(); }, 10000);
// -- Schedule task #2 --
taskRegistrar.addFixedRateTask(() -> { secondTask(); }, 1000);
}
private void firstTask() {
// -- Your first task logic goes here! --
}
private void secondTask() {
// -- Your second task logic goes here! --
}
}
除了米歇尔接受的答案:
使用Spring引导时,与其直接创建TaskScheduler,不如为其使用构建器更明智:
@Bean
public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
return builder.build();
}
生成器在 org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
中定义。因此,使用这种方法,您将获得与未使用 @EnableWebSocket 完全相同的调度程序(即,它将使用来自 spring 配置属性等的池大小)。