SpringBoot坚持学习第九天:集成定时任务Quartz

版权声明:欢迎转载大宇的博客,转载请注明出处: https://blog.csdn.net/yanluandai1985/article/details/86065111

一、Quartz是什么

        导入讲解Quartz的深度好文:Quartz使用总结 作者:路边飞

        Quartz是一个任务调度框架。比如你遇到这样的问题。

  • 想每月25号,信用卡自动还款
  • 想每年4月1日自己给当年暗恋女神发一封匿名贺卡
  • 想每隔1小时,备份一下自己的爱情动作片 学习笔记到云盘

        这些问题总结起来就是:在某一个有规律的时间点干某件事。并且时间的触发的条件可以非常复杂(比如每月最后一个工作日的17:50),复杂到需要一个专门的框架来干这个事。 Quartz就是来干这样的事,你给它一个触发条件的定义,它负责到了时间点,触发相应的Job起来干活。

二、SpringBoot内置定时器

         首先导入依赖。

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

SpringBoot内置的定时器需要使用@Scheduled注解的cron属性来指明运行周期。

cron属性共有七位,分别是 秒、分、小时、每日、每月、星期、年

0 15 10 ? * *   每天10:15运行

0 * 14 * * ?      每天14点到15点之间每分钟运行一次,开始于14:00,结束于14:59。

0 0/5 14 * * ?  每天14点到15点每5分钟运行一次,开始于14:00,结束于14:55。

0 15 10 15 * ? 每月15日10:15分运行。

@Component
public class SchedulerTask {
    @Scheduled(cron = "*/6 * * * * ?")
    private void process() {
        System.out.println("现在时间:" + dateToDateStr(new Date(), DEFAULT_FORMAT));
    }
}
@SpringBootApplication
@EnableScheduling
public class QuartzApplication {
    public static void main(String[] args) {
        SpringApplication.run(QuartzApplication.class, args);
    }
}

   

每隔六秒执行一次 。除了使用cron属性以外,还能换成fixedRate固定的周期。

  • @Scheduled(fixedRate = 6000)  :上一次开始执行时间点之后 6 秒再执行。
  • @Scheduled(fixedDelay = 6000):上一次执行完毕时间点之后 6 秒再执行。

三、Quartz

       quartz音括子。

       Quartz有四个核心概念:

Job(任务)   

        定义任务的执行逻辑,在实现接口的 execute 方法中编写所需要定时执行的 Job(任务)

JobDetail(任务信息)

        JobDetail 定义的是任务数据,而真正的执行逻辑是在Job中。

Trigger(触发器)

        触发 Job 执行的时间触发规则,主要有 SimpleTrigger 和 CronTrigger 这两个子类。当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger 是最适合的选择;而CronTrigger 则可以通过 Cron 表达式定义出各种复杂时间规则的调度方案

Scheduler(调度器)

        调度器就相当于一个容器,用于绑定Trigger与JobDetail。两者在 Scheduler 中拥有各自的不同的组及名称。   

         为什么设计成JobDetail + Job,不直接使用Job?这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。 

四、SimpleSchedule 

        使用SimpleTrgger表明定时任务不是很复杂,仅仅运行一次或者按照指定的周期进行运行。

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

        先编写一个Job接口实现,编写它的任务方法,并表面其 运行时需要提供的数据信息。Job 运行时的信息保存在 JobDataMap 实例中。需要由JobDetail来指明。

@Getter
@Setter
public class SampleJob extends QuartzJobBean {

    private String name;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println(String.format("Hello %s!", this.name));
    }
}

再编写一个JobDetail来描述 Job 的实现类及其他相关的运行时信息。

    @Bean
    public JobDetail generateJobDetail() {
        return JobBuilder.newJob(SampleJob.class).withIdentity("sampleJob").usingJobData("name", "World").
                storeDurably().build();
    }

最后再编写触发规则

    @Bean
    public Trigger sampleJobTrigger() {
        //触发规则:指定每两秒执行一次
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(2).repeatForever();
        //将触发规则与JobDetail绑定
        return TriggerBuilder.newTrigger().forJob(generateJobDetail())
                .withIdentity("sampleTrigger").withSchedule(scheduleBuilder).build();
    }

最后将这个触发规则Trigger与任务对象JobDetail注册到同一个容器Scheduler中。

@Configuration
public class SampleScheduler {

    @Bean
    public JobDetail generateJobDetail(){...}

    @Bean
    public Trigger sampleJobTrigger() {...}
}

  

五、CronSchedule 复杂调度任务

        按照上述编写习惯,首先先编写一个Job接口实现,然后再编写一个JobDetail来包装Job接口实现。再编写一个触发规则Trigger。最后将JobDetail与Trigger绑定到一起并加入Schedule中。

public class ScheduledJob implements Job {
    @Override  
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("schedule job1 is running ...");
    }  
} 
@Component
public class MySchedule {

    /**
     * 生成Schedule的工厂
     */
    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    public void startScheduleTask() throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        scheduleJob1(scheduler);
    }

    private void scheduleJob1(Scheduler scheduler) throws SchedulerException {
        //先通过Job生成JobDetail
        JobDetail jobDetail = JobBuilder.newJob(ScheduledJob.class).
withIdentity("job1", "groupName").build();
        //核心:编写cron周期规则
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/6 * * * * ?");
        //Trigger
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().
withIdentity("trigger1", "group1").withSchedule(scheduleBuilder).build();
        scheduler.scheduleJob(jobDetail, cronTrigger);
    }
}

最后在项目启动的时候,开启定时任务

@Component
public class MyStartupRunner implements CommandLineRunner {

    @Autowired
    public MySchedule scheduleJobs;

    @Override
    public void run(String... args) throws Exception {
        scheduleJobs.startScheduleTask();
        System.out.println(">>>>>>>>>>>>>>>定时任务开始执行<<<<<<<<<<<<<");
    }
}

  

猜你喜欢

转载自blog.csdn.net/yanluandai1985/article/details/86065111