Java web

框架篇-定时任务(三) - Quartz

2020-04-28  本文已影响0人  秃头猿猿

1.定时任务 - Quartz

1.1 前言

我们刚刚使用Spring自带的定时任务,Spring除了自己的定时任务以外,还可以继承其他的定时任务,如: Quartz

1.2 介绍

image-20200428134540388.png

Quartz核心对象如下:

1.3 Helloword

1.3.1 创建SpringBoot项目

image-20200428140415152.png image-20200428151222677.png

1.3.2 查看Quartz依赖

1.3.3 修改启动类

在启动类上添加开启任务调度

image-20200428141537527.png

1.3.4 撰写自定义任务

package com.task.quartz.task;

import org.springframework.stereotype.Component;

@Component
public class HelloTask {
    public static void task() {
        System.out.println("=========任务1=========");
    }
}

1.3.5 配置Job

通过先前我们只要,一个任务需要实现Job接口,上面的HelloTask并没有实现Job接口。也就是Quartz并不知道我们的HelloTask 是一个 Job。因此我们可以借助MethodInvokingJobDetailFactoryBean来进行配置JobDetail

JobDetail 任务细节,里面包含了 任务,以及任务调度的方案和策略。例如是否并发执行等等。

@Bean
    public MethodInvokingJobDetailFactoryBean jobDetail(HelloTask task) {
        MethodInvokingJobDetailFactoryBean detailFactoryBean = new MethodInvokingJobDetailFactoryBean();
        // 设置是否并发运行
        detailFactoryBean.setConcurrent(true);
        // 注册 Job
        detailFactoryBean.setTargetClass(HelloTask.class);
        // 设置要执行的方法
        detailFactoryBean.setTargetMethod("task");
        return detailFactoryBean;

    }

1.3.6 配置触发器

1.3.7 配置 Scheduler 容器

@Bean
    public SchedulerFactoryBean scheduler(Trigger cronTrigger) {
        SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
        // 容器启动时,会更新已经存在的任务
        factoryBean.setOverwriteExistingJobs(true);
        // 设置延迟启动时间 单位 秒
        factoryBean.setStartupDelay(1);
        // 注册触发器
        factoryBean.setTriggers(cronTrigger);
        return factoryBean;
    }

1.3.8 启动测试

image-20200428150745359.png

这样我们一个Helloword就写完了。但是我们发现有一些缺点:

因此我们有没有方式去简化呢,当然是有的的。

1.4 简化 Hellworld

为了更加直观测试,我们重新创建一个项目。

1.4.1 创建项目

image-20200428151131872.png

1.4.2 修改启动类

image-20200428152503025.png

1.4.3 撰写任务类1

package com.quartz.task;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;


public class HelloTask extends QuartzJobBean {
    /**
    *  在这个方法里面撰写
    */
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println("=====任务1 开始======");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("=====任务1 结束======");
    }
}

1.4.4 撰写任务类2

package com.quartz.task;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;


public class HelloTask2 extends QuartzJobBean {
    /**
    *  在这个方法里面撰写
    */
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println("=====任务2 开始======");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("=====任务2 结束======");
    }
}

1.4.5 撰写配置类

package com.quartz.task;

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TaskConfig {
    /**
     *  创建 JobDetail 绑定任务1
     *
     */
    @Bean
    public JobDetail uploadTaskDetail() {
        return JobBuilder.newJob(HelloTask.class).withIdentity("helloTask").storeDurably().build();
    }

    /**
     *  创建 JobDetail 绑定任务2
     *
     */
    @Bean
    public JobDetail uploadTaskDetail2() {
        return JobBuilder.newJob(HelloTask2.class).withIdentity("helloTask2").storeDurably().build();
    }

    /**
     * 创建触发器 1 并且与任务1绑定
     * @return
     */
    @Bean
    public Trigger updateTaskTrigger() {
        CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule("*/2 * * * * ?");
        return TriggerBuilder.newTrigger().forJob(uploadTaskDetail()).withSchedule(builder).build();
    }

    /**
     * 创建触发器 2 并且与任务2绑定
     * @return
     */
    @Bean
    public Trigger updateTaskTrigger2() {
        CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule("*/2 * * * * ?");
        return TriggerBuilder.newTrigger().forJob(uploadTaskDetail2()).withSchedule(builder).build();
    }
}

1.4.6 测试

image-20200428155113968.png

满足我们的要求。

1.5 线程池执行任务

代码地址:https://github.com/smallCodeWangzh/quartz-demo-task.git

1.5.1创建项目

还是一样,我们创建一个新的项目,并且导入Quartz依赖。这里就不截图演示了。

image-20200428155528515.png

1.5.2 添加任务

我们创建两个service。一个是GoodsService,一个是BrandService这两个Service的方法彼此执行各自查询功能

image-20200428161935300.png
package com.quartz.task.service;

import org.springframework.stereotype.Service;

@Service
public class GoodsService {
    public void findAllGoods() {
        System.out.println("====任务1: 查询 商品 开始=====");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("=======任务1: 查询商品结束 ==========");
    }
}

创建 BrandService

image-20200428162110199.png
package com.quartz.task.service;

import org.springframework.stereotype.Service;

@Service
public class BrandService {
    public void findAllBrand() {
        System.out.println("====任务2: 查询 品牌 开始=====");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("=======任务2: 查询 品牌 结束 ==========");
    }
}

1.5.3 编写工具类

由于我们的Service对象由Spring容器管理,所以我们需要编写一个工具类用来获取容器里面的对象

image-20200428162848565.png
package com.quartz.task.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class TaskUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        TaskUtil.applicationContext = applicationContext;
    }
    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }

    public static <T> T getBean(String name, Class<T> requiredType) {
        return applicationContext.getBean(name, requiredType);
    }
    
    public static <T> T getBean(Class<T> requiredType) {
        return applicationContext.getBean(requiredType);
    }
}

1.5.4 增加JobDetail

image-20200428162231656.png
package com.quartz.task;

import com.quartz.task.service.BrandService;
import com.quartz.task.service.GoodsService;
import com.quartz.task.util.TaskUtil;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ScheduleJob extends QuartzJobBean {
    // 创建线程池
    private ExecutorService executorService = Executors.newFixedThreadPool(10);

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        GoodsService goodsService = TaskUtil.getBean(GoodsService.class);
        BrandService brandService = TaskUtil.getBean(BrandService.class);
        executorService.execute(() -> {
            goodsService.findAllGoods();
        });
        executorService.execute(() ->{
            brandService.findAllBrand();
        });
    }
}

1.5.5 增加配置

package com.quartz.task.config;

import com.quartz.task.ScheduleJob;
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TaskConfig {
    /**
     *  创建 JobDetail 绑定任务1
     *
     */
    @Bean
    public JobDetail uploadTaskDetail() {
        return JobBuilder.newJob(ScheduleJob.class).withIdentity("helloTask").storeDurably().build();
    }


    /**
     * 创建触发器 1 并且与任务1绑定
     * @return
     */
    @Bean
    public Trigger updateTaskTrigger() {
        CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule("*/10 * * * * ?");
        return TriggerBuilder.newTrigger().forJob(uploadTaskDetail()).withSchedule(builder).build();
    }

}

image-20200428163819404.png

当然上述做法,在实际项目中不合理,有很多需要优化的地方,这只是提供一个思路。

同时上述只是定时任务入门,如果牵涉到分布式定时任务,或者说项目需求是动态的定时任务,那么就需要视需求而定。

上一篇下一篇

猜你喜欢

热点阅读