• springboot + schedule


    参考文章:https://blog.csdn.net/sinianliushui/article/details/78841713

    参考文章: https://blog.csdn.net/hao7030187/article/details/79077464

    参考文章:https://www.cnblogs.com/domi22/p/9418433.html

    springboot的SchedulerTask相对Quartz来说,简单方便,可试用于小型的job处理。

    因没法持久化因此不支持分布式部署,和动态数据源配置。

    如果要

    一、简易配置

    1. 开启定时任务,在启动类添加以下注解

    @EnableScheduling

    2. 创建并发配置,并发线程

    @Component
    public class SchedulerConfig implements SchedulingConfigurer {
    
        /**
         * 设置定时任务
         * @param scheduledTaskRegistrar
         */
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
            scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
        }
    }

    3. 创建scheduler,以下是没5秒触发一次,cron表达式有cron在线生成器可以用

    @Component
    @Slf4j
    public class SchedulerTask {
    
        @Scheduled(cron="0/5 * * * * ? ")
        public void testTask(){
            DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            log.debug(Thread.currentThread() + "  " + sdf.format(new Date()));
        }
        @Scheduled(cron="0/5 * * * * ? ")
        public void test2Task(){
            DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            log.debug(Thread.currentThread() + "  " + sdf.format(new Date()));
        }

    }

    二、分开配置

    如下例子,如果只有一个Bean,名字为taskScheduler,或者方法名为taskScheduler则会作为自动的Scheduler。使用 @Scheduled即对应的是此TaskScheduler。

    参见文章:  https://blog.csdn.net/sinianliushui/article/details/78841713

    /**
     * description: 
     * 定时任务
     * @Autor:DennyZhao
     * @Date:2019/2/15
     * @Version: 1.0.0
     */
    @Component
    @EnableScheduling
    public class SchedulerConfig {
        /** task相关的属性文件 **/
        @Autowired
        private TaskProperties taskProperties;
    
        /**
         * 设备组织用Job
         * @return
         */
       @Bean("DeviceJob")
       public TaskScheduler initDeviceOrgTask(){
           ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
           //线程池大小
           scheduler.setPoolSize(taskProperties.getDeviceThreadCount());
           //线程名字前缀
           scheduler.setThreadNamePrefix("taskThread-deviceTask: ");
           scheduler.initialize();
           Trigger trigger = new CronTrigger(taskProperties.getDeviceOrgCron());
           scheduler.schedule(new DeviceOrgTask(), trigger);
           return scheduler;
       }
    
        /**
         * Jpush用Job
         * @return
         */
        @Bean("JpushJob")
        public TaskScheduler initJpushTask(){
            ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
            //线程池大小
            scheduler.setPoolSize(taskProperties.getJpushThreadCount());
            //线程名字前缀
            scheduler.setThreadNamePrefix("taskThread-jpushTask: ");
            scheduler.initialize();
            Trigger trigger = new CronTrigger(taskProperties.getJpushReportCron());
            scheduler.schedule(new JpushReportTask(), trigger);
            return scheduler;
        }
    }

    TaskPropertis

    /**
     * description: 
     * JPUSH执行任务相关参数
     *
     * @Autor:DennyZhao
     * @Date:2019/2/15
     * @Version: 1.0.0
     */
    @Component
    @PropertySource("classpath:task-config.properties")
    @ConfigurationProperties(prefix="task")
    @Data
    public class TaskProperties {
    
        /** 极光推送appKey **/
        private String jpushAppKey;
        /** 极光推送secretKey **/
        private String jpushSecretKey;
    
    
    
        /** 设备JOB的线程数 **/
        private int deviceThreadCount;
        /** 设备组织Cron **/
        private String deviceOrgCron;
        /** Jpush的JOB线程数 **/
        private int jpushThreadCount;
        /** Jpush的推送报告Cron **/
        private String jpushReportCron;
    }

    创建类实现Runable接口即可使用。

    @Component
    @Slf4j
    public class DeviceOrgTask implements Runnable {
    
        @Override
        public void run() {
            DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            log.debug(Thread.currentThread() + "  " + sdf.format(new Date()));
        }
    }

     

    问题: 

         1.  从以上的一简易配置中(如果不添加SchedulerConfig)也可以运行,发现如果在方法中添加Thread.sleep(),会影响下面方法的运行和下次的运行时间。

            因为默认的 ConcurrentTaskScheduler 计划执行器采用Executors.newSingleThreadScheduledExecutor() 实现单线程的执行器。

            因此要使用异步: 采用异步的方式执行调度任务,配置 Spring 的 @EnableAsync,在执行定时任务的方法上标注 @Async配置任务执行。注意线程池大小要依据单个任务时间和任务间隔。

          2. 分布式重复执行

               1.使用 redis分布式锁setnx命令 来控制是否已经存在有任务在执行。

                2.使用spring的shedLock,创建一个数据表,先更新者执行,非更新者不执行。

                   参见:https://segmentfault.com/a/1190000011975027

          3. 主程序挂掉后,job停止,数据丢失

                使用redis记录执行时间。

     异常:  

    [ERROR] 2019-03-21 14:00:38,757 >>> org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler.handleError(TaskUtils.java:96)
    [massage] Unexpected error occurred in scheduled task.
    java.lang.IllegalStateException: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@8f84321 has been closed already

    使用applicationContext未获取到bean异常。

    因EnabledTask会使得任务在执行完后closeContext导致,在配置文件添加:

    spring.cloud.task.closecontext_enable=false

    高版本用 spring.cloud.task.close_context_enabled=false

    参考文章: https://stackoverflow.com/questions/48933575/spring-cloud-task-scheduling-context-closed

  • 相关阅读:
    最近花了几个夜晚帮师妹整了一个企业网站
    英文学习网站
    Visual Studio 常用快捷键 (二)
    Visual Studio 常用快捷键
    学习英文之社区,博客及源码
    CodeForces 676D代码 哪里有问题呢?
    线程中调用python win32com
    Python 打包工具cx_freeze 问题记录及解决办法
    HDU1301 Jungle Roads
    HDU 1875 畅通工程再续
  • 原文地址:https://www.cnblogs.com/DennyZhao/p/10385533.html
Copyright © 2020-2023  润新知