開發環境: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接口),定時任務也需要線程池,可能這里面有什么沖突
后記:最主要的問題,還是基礎太差