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

 

    從報錯信息上面看,是Bean named 'defaultSockJsTaskScheduler' is expected to be of type 'org.springframework.scheduling.TaskScheduler' but was actually of type 'org.springframework.beans.factory.support.NullBean',注入的類型不對,隨后百度。
  然而百度里出現這樣的問題多是重復引入導致包沖突或者是引入了錯誤的包,百思不得其解,我是哪里不對啊,我認真的對了一遍代碼,沒錯啊。
就在這個時候,突然想起來一句話,說:當你在學習一個新東西新技術的時候,你只需要一個單純的環境,避免一切可能和不可能的干擾,於是我新建一個項目,按照官網的示例代碼寫了一遍。好嘛,一點毛病也沒有,那么問題肯定是定時任務和我現在環境有沖突,但是這個沖突會是什么導致的呢?
  我又看了一遍異常信息,突然發現,報錯信息里面一個地方defaultSockJsTaskScheduler,SockJsTask,那么會不會是和websocket環境沖突了,測試了一下,將websocket去掉后,定時任務正常,終於找到你了。
之后感謝下面這篇博客,幫助我解決了問題
 
我的操作:
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接口),定時任務也需要線程池,可能這里面有什么沖突

后記:最主要的問題,還是基礎太差


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM