10

I have a spring boot application with websockets:

@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
@EnableScheduling
public class TestApplication {

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

WebSocket config:

@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();
    }    
}

It worked fine. Then I added @EnableSheduled and created Scheduling component:

@Component
public class ScheduledTask {

    @Scheduled(fixedRate = 1000)
    public void printHello() {
        System.out.println("hello");
    }
}

and get an exception:

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]

I tried to remove websockets from my project. After this, everything starts works fine. How to fix it?

3 Answers3

14

This can be fixed by manually defining a TaskScheduler bean, see for example this post: https://medium.com/@jing.xue/spring-boot-application-startup-error-with-websocket-enabled-832456bb2e

So, in Java terms, this would be

@Bean
public TaskScheduler taskScheduler() {
    TaskScheduler scheduler = new ThreadPoolTaskScheduler();

    scheduler.setPoolSize(2);
    scheduler.setThreadNamePrefix("scheduled-task-");
    scheduler.setDaemon(true);

    return scheduler;
}
Michel
  • 603
  • 6
  • 15
  • Thank you! Actually the type of scheduler needs to be ThreadPoolTaskScheduler, too to have access too setPoolSize etc.: @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(2); scheduler.setThreadNamePrefix("scheduled-task-"); scheduler.setDaemon(true); return scheduler; } – Stefan Sep 10 '20 at 10:02
9

In addition to accepted answer from Michel:

When using Spring Boot, instead of creating TaskScheduler directly, it may be wiser to use a builder for it:

@Bean
public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
    return builder.build();
}

The builder is defined in org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration. So, using this approach you will get exactly the same scheduler as if you were not using @EnableWebSocket (i.e. it will use pool size from spring configuration properties, etc.).

Alexey Osipov
  • 91
  • 1
  • 2
0

There is a more convenient way to solve this. you can annotate your custom scheduler class with @Configurable and @EnableScheduling and implement SchedulingConfigurer interface in it. Then you should implement the configureTasks method which has a ScheduledTaskRegistrar object as it's input argument. Using this object you can define and execute any type of scheduled tasks. Just remember you need to inform the Spring Framework Context regarding this, in the parent Bean.

Parent Bean class's constructor :

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! --
    }
}
Majid
  • 336
  • 2
  • 13