webSocket+定时器Springboot启动报错

websocket配置

package com.ckh.springboot04.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
@EnableWebSocket
public class WebSocketConfig {
     
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
     
        return new ServerEndpointExporter();
    }
}
package com.ckh.springboot04.websocket;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * websocket相关的服务
 */
@ServerEndpoint("/websocket")
@Component
@Slf4j
public class WebSocketServer {
     

    /**
     * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static int onlineCount = 0;

    /**
     * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
     */
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();

    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;


    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
     
        this.session = session;
        //加入set中
        webSocketSet.add(this);
        //在线数加1
        addOnlineCount();
        log.info("有新窗口开始监听,当前在线人数为" + getOnlineCount());
        System.out.println("websocket连接成功");
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
     
        //从set中删除
        webSocketSet.remove(this);
        //在线数减1
        subOnlineCount();
        log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
     
        log.info("收到来自客户端的信息:" + message);
    }

    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
     
        log.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送 ,即服务器向客户端发送message
     */
    public void sendMessage(String message) throws IOException {
     
//        this.session.getBasicRemote().sendText(message);
        for (WebSocketServer webSocket : webSocketSet) {
     
            log.info("【websocket消息】广播消息, message={}", message);
            try {
     
                webSocket.session.getBasicRemote().sendText(message);
            } catch (Exception e) {
     
                e.printStackTrace();
            }
        }
    }


    public static synchronized int getOnlineCount() {
     
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
     
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
     
        WebSocketServer.onlineCount--;
    }


}

sringboot 内置定时器

package com.ckh.springboot04.component;

import com.ckh.springboot04.dao.AdminRepository;
import com.ckh.springboot04.entities.Admin;
import org.apache.poi.ss.usermodel.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;

/*
* 定时任务
* 判断当前admin的lockedFlag
* 到时间就解锁
* */
@Component
public class ScheduledTask {
     
    @Autowired
    AdminRepository adminRepository;

    @Scheduled(cron = "0/10 * * * * ?") //每10秒执行一次
    public void scheduledTaskByCorn() {
     

        List<Admin> admins = adminRepository.findAll();
        for (Admin admin : admins){
     
            Date lockedToTime = admin.getLockedToTime();
            if (lockedToTime != null){
      //当前用户状态为锁定
                Date current_date = new Date();
                int compare = current_date.compareTo(lockedToTime); //current_date < lockedToTime 返回-1;等于0;大于1
                if (compare >= 0){
     
                    // lockedToTime <=current_date
                    //超过锁定日期,可以解锁了
                    admin.setLockedToTime(null);
                    admin.setLockedFlag(true);

                    admin.setUpdateTime(null);
                    adminRepository.save(admin);//更新数据库
                }
            }

        }

    }

}

在启动类上加@EnableScheduling

package com.ckh.springboot04;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableScheduling;


@SpringBootApplication
@EnableScheduling
public class SpringBoot04WebRestfulcrudApplication {
     

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

}

但是启动却报错:
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’

参考这两篇博客,终于找到解决方案:
添加一个配置类:

package com.ckh.springboot04.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也是定时任务(心跳检测)自带线程池,然后自定义的定时任务也需要重新定义一个线程池。才能保证两者不纠缠在一起。。

理解浅显,望各位指正。

参考博客链接:
https://www.cnblogs.com/threadj/articles/10631193.html
https://blog.csdn.net/u013565163/article/details/80659828

你可能感兴趣的:(spring,boot,java)