Quartz | 青训营笔记

72 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天

时间轮介绍

Quartz.png

从具体实现来看,时间轮 是一个基于 「数组」 实现的 「循环队列」 ,数组的每个元素被称为 「槽(slot)」 ,每个槽中存储着一个 「任务列表」 ,这个任务列表的实现较为多样,可以是 「由双向链表实现」 ,也可以是 「由数组实现」。除了基本的存储结构,时间轮还有一根用于指示当前时间的指针,这根指针同时也用于触发所指向的时间槽内任务。该指针以恒定的速度旋转,每经过一个槽即走过一个单位时间*(所以也可以将槽称为时间槽,因为它即表示时间刻度,也表示存储空间)*,旋转一圈则走过时间轮的一个生命周期。

而上图采用的是多层级时间轮 多层级时间轮从逻辑上和我们日常使用的时钟颇为相似,上一层级的时间轮中的一个时间槽(单位时间)等于下一层级的时间轮的一个时间周期。

Quartz核心概念

  • Scheduler为调度器负责整个定时系统的调度,内部通过线程池进行调度,下文阐述。

  • Trigger为触发器记录着调度任务的时间规则,主要有四种类型:SimpleTrigger、CronTrigger、DataIntervalTrigger、NthIncludedTrigger,在项目中常用的为:SimpleTrigger和CronTrigger。

  • JobDetail为定时任务的信息载体,可以记录Job的名字、组及任务执行的具体类和任务执行所需要的参数

  • Job为任务的真正执行体,承载着具体的业务逻辑。

先由SchedulerFactory创建Scheduler调度器后,由调度器去调取即将执行的Trigger,执行时获取到对于的JobDetail信息,找到对应的Job类执行业务逻辑。

Spring Boot 实现

下面实现的是一个使用Quartz定时将Redis的数据传到mysql中同步。

1. 引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

2. 配置Quartz

@Configuration
public class QuartzConfig {
    private static final String LIKE_TASK_IDENTITY = "LikeTaskQuartz";

    @Bean
    public JobDetail quartzDetail(){
        return JobBuilder.newJob(FavoriteTask.class).withIdentity(LIKE_TASK_IDENTITY).storeDurably().build();
    }

    @Bean
    public Trigger quartzTrigger(){
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInMinutes(15) 
                .repeatForever();
        return TriggerBuilder.newTrigger().forJob(quartzDetail())
                .withIdentity(LIKE_TASK_IDENTITY)
                .withSchedule(scheduleBuilder)
                .build();
    }
}

3. Job类实现

@Component
public class FavoriteTask extends QuartzJobBean {

    @Autowired
    FavoriteService favoriteService;
    @Autowired
    CommentService commentService;

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) {

        log.info("LikeTask-------- {}", sdf.format(new Date()));

        //将 Redis 里的点赞信息同步到数据库里
        favoriteService.transFavoriteFromRedis2DB();
        favoriteService.transFavoriteCountFromRedis2DB();
        commentService.transCommentCountFromRedis2DB();
    }
}