SpringBoot——定时任务+WebSocket(问题)
开发环境:win7 + idea2018 + jdk 1.8 + springboot 2.x
记一次出现问题,我在项目中先集成了websocket环境,并且测试通过,之后想要模拟实时推送的效果,虽然可以直接使用线程类进行模拟,但是想到最近看到了定时任务,就像试一试,没有想到,这不试不知道啊,这里有个坑,主要原因还是由于个人的基础太浅薄,英文水平太辣鸡。
WebSocket环境搭建可以参考我之前的记录(https://www.cnblogs.com/threadj/p/10552904.html),在这里只记录本次出现问题
首先是搭建定时任务环境:
1、创建定时任务,如下使用@Scheduled注解并指定其时间周期,该方法为一个定时任务,使用@Component将定时任务类加入Spring管理
未验证:都说定时任务只能放在一个单独的类里面,就比如说不可以在@Controller中直接用@Scheduled注解标注一个定时任务,这个暂时我还没有进行验证
package com.zyzj.site_civilization.task; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.zyzj.site_civilization.net.websocket.WebSocketHandler; import com.zyzj.site_civilization.net.websocket.WebSocketPool; import com.zyzj.site_civilization.service.EquipmentService; import com.zyzj.site_civilization.util.CommonUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.websocket.Session; import java.sql.Timestamp; import java.util.Date; import java.util.List; import java.util.Map; @Slf4j @Component public class DataSupportTask implements InitializingBean { @Autowired private EquipmentService equipmentService; private Map<String, Session> map; private ObjectMapper mapper = new ObjectMapper(); private List<Equipment> equipmentList; public EquipmentDataHistory init(){ //初始化数据 类 data = new 类();//嘿嘿 return data; } //定时任务执行体,5秒执行一次,fixedRate具体意义不说了,因为我忘了 @Scheduled(fixedRate = 5000) public void dataSupport(){ map = WebSocketPool.getSession(); if (map.size() > 0){ try { WebSocketHandler.sendMessageAll(mapper.writeValueAsString(init())); } catch (JsonProcessingException e) { e.printStackTrace(); } }else { log.info("当前无在线用户"); } } @Override public void afterPropertiesSet() throws Exception { //这个方法会在IOC对当前类进行实例化时,当所有的依赖注入完成后调用此方法 //我不知道怎么表达对不对 //我这里因为我在init方法中需要使用到这个数据,所以在这里初始化初始化 equipmentList = equipmentService.queryEntityListAll(); } }
2、在启动类加上@EnableScheduling注解,到此定时任务类完成创建
package com.zyzj.site_civilization; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } }
官方文档参考:https://spring.io/guides/gs/scheduling-tasks/
然而,在我启动程序的时候出事了,我可是看着官方例子写的好不好,
出错信息如下:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2019-03-30 17:28:17.789 ERROR 17644 --- [ main] o.s.boot.SpringApplication : Application run failed 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.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:224) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1115) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1082) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.resolveSchedulerBean(ScheduledAnnotationBeanPostProcessor.java:313) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:254) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:231) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:103) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:163) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at com.zyzj.site_civilization.SiteCivilizationApplication.main(SiteCivilizationApplication.java:12) [classes/:na] Process finished with exit code 1
package com.jian.test.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @Configuration public class ScheduledConfig { @Bean public TaskScheduler taskScheduler(){ ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(10); taskScheduler.initialize(); return taskScheduler; } }
待验证:至于为什么会出现这样的问题,猜测可能是因为websocket也需要定时任务(心跳检测),定时任务其实也是依赖于一个新的线程,这些线程需要管理起来,需要线程池,websocket里面好像默认实现了一个ThreadPoolTaskScheduler,(ThreadPoolTaskScheduler实现了TaskScheduler接口),定时任务也需要线程池,可能这里面有什么冲突
后记:最主要的问题,还是基础太差