zoukankan      html  css  js  c++  java
  • quartz开源任务调度框架

    0.集群和分布式

    我的理解:

    集群:同一个服务部署多个服务器,也就是单机版多部署几台服务器,一台不能用了,另一台还可以接着用(调度)

    分布式:多个集群组成一个完整项目,系统之间的耦合度降低,服务的复用性更高,分成了多个子系统

     

    **: 

    1.Quartz是什么?(任务调度框架)

    Quartz官方网站:http://www.quartz-scheduler.org
    1. Quartz是一个功能丰富的、开源任务调度框架,几乎可以集成到任何Java应用中,小 到单体引用,大到大型电子商务系统;

    2. Quartz可以用来创建和执行成千上万的简单或复杂调度任务;

    3. Quartz的任务被定义成一组标准的Java组件,几乎可以执行任何编程任务;

    4. Quartz包含很多企业级功能,包括JTA事务(分布式事务)和集群

    2.Quartz可以做什么

    1. 定时发送邮件、短信

    2. 定时进行数据同步

    3. 定时删除超时订单

    3.Quartz的核心API

    1. Job:你想要调度器执行的任务组件需要实现的接口

    2. JobDetail:描述任务详细细节(描述任务名称、任务组)

    3. JobBuilder:用户创建JobDetail

    4. Trigger:定义任务的调度时机(规则)
    SimpleTrigger:定义任务开始时间、结束时间、每隔多长时间执行、执行多少次、 执行多久
    CronTrigger:使用Cron表达式定义执行规则

    5. TriggerBudiler:创建Trigger触发器
    6. Scheduler:使用Trigger定义规则去调度(执行)任务

    7. JobDataMap:JobDetail和Trigger可以通过它给Job传递参数
    8. JobKey: 封装了Job的name和group("工作的名称", "工作的组")    TriggerKey: ("触发器的名称", "触发器的组")

    9. JobExectionContext

    4.代码

    4.1创建Quartz的过程
    First

    package com.etoak.simple; import com.etoak.job.HelloJob; import org.quartz.
    *; import org.quartz.impl.StdSchedulerFactory; public class First { public static void main(String[] args) throws SchedulerException { //1.创建jobDetail //JObKey封装了Job的name和group JobKey jobKey = new JobKey("hello","hello"); //定义工作并将其绑定到我们的HelloJob类 //.withIdentity("工作的名称", "工作的组") JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//创建了一个JobDetail,绑定任务job .withIdentity(jobKey) .build(); //2.创建Trigger(触发器)==>定义规则 TriggerKey triggerKey = new TriggerKey("hello","hello"); //TriggerBuilder - 用于定义/构建触发器实例。 //.withIdentity("触发器的名称", "触发器的组") SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(triggerKey) .withSchedule(SimpleScheduleBuilder //SimpleScheduleBuilder是简单调用触发器,它只能指定触发的间隔时间和执行次数; .simpleSchedule()//创建一个SimpleScheduleBuilder .withIntervalInSeconds(5)//每个五秒执行一次 .repeatForever()//一直执行 ).build(); //3.创建Scheduler==>执行Trigger定义的规则 Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.scheduleJob(jobDetail,trigger); scheduler.start(); } }
    ==========================================================================================================================================
    Second
    package com.etoak.simple;
    import com.etoak.job.HelloJob;
    import org.quartz.*;
    import org.quartz.impl.StdSchedulerFactory;

    import java.text.SimpleDateFormat;
    import java.util.Date;

    public class Second {

    public static void main(String[] args) throws SchedulerException {
    JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
    .withIdentity("hello").build();
    Date current = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    System.out.println("当前时间->" + sdf.format(current));
    Date date = new Date(current.getTime() + 5000L);

    SimpleTrigger trigger = TriggerBuilder.newTrigger()
    .withIdentity("hello")
    .startAt(date)//表示触发器首次被触发的时间;
    .withSchedule(SimpleScheduleBuilder
    .simpleSchedule()
    .withIntervalInSeconds(5)//每个五秒执行一次
    .withRepeatCount(10)//执行十次,加上第一次是十一次
    ).build();

    Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    scheduler.scheduleJob(jobDetail,trigger);
    scheduler.start();
    }
    }
    ==============================================================================================================================
    Third
    package com.etoak.simple;
    import com.etoak.job.HelloJob;
    import org.quartz.*;
    import org.quartz.impl.StdSchedulerFactory;

    import java.util.Date;

    public class Third {
    public static void main(String[] args) throws SchedulerException {
    JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
    .withIdentity("hello")
    .build();
    //获取30秒后的时间
    Date date = new Date(System.currentTimeMillis() + 1000L * 30);
    SimpleTrigger trigger = TriggerBuilder.newTrigger()
    .withIdentity("hello")
    .endAt(date)//30秒后结束
    .withSchedule(SimpleScheduleBuilder.simpleSchedule()
    .withIntervalInSeconds(5)
    .repeatForever()
    ).build();
    Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    scheduler.scheduleJob(jobDetail,trigger);
    scheduler.start();
    }
    }
    ===========================================依赖===================================================================
    
    
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.etoak.et2006.quartz</groupId>
    <artifactId>quartz-java</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
    <!--quartz依赖-->
    <dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
    </dependency>
    <!--日志-->
    <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
    </dependency>
    </dependencies>

    </project>
     

    5.测试Cron表达式

    package com.etoak.cron;
    
    import com.etoak.job.HelloJob;
    import org.quartz.*;
    import org.quartz.impl.StdSchedulerFactory;
    
    public class CronTest  {
        public static void main(String[] args) throws SchedulerException {
            JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                    .withIdentity("hello")//身份信息
                    .build();
    
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("hello")
                    .withSchedule(
                            CronScheduleBuilder//.cronSchedule("*/5 * * * * ?")//秒分时天月周
                            //.cronSchedule("0 33 11 ? * MON-FRI")
                             .cronSchedule("0 0/1 11 ? * MON-FRI")
                    ).build();
    
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.scheduleJob(jobDetail,trigger);
            scheduler.start();
    
        }
    
    }

    6.SpringMVC整合单机版Quartz

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    <!--单机版-->
        <!--1.创建任务类-->
        <bean id="emailJob" class="com.etoak.job.EmailJob" />
        <!--2.JobDetail-->
        <bean id="emailJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
            <!-- 任务名称和任务组名称 -->
            <property name="name" value="emailJob" />
            <property name="group" value="emailJob" />
            <!-- 执行的目标任务对象(spring bean) -->
            <property name="targetObject" ref="emailJob" />
            <!--任务对象的方法-->
            <property name="targetMethod" value="sendEmail" />
        </bean>
        <!--3.Trigger-->
        <bean id="emailTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
            <property name="name" value="emailTrigger" />
            <property name="group" value="emailTrigger" />
            <property name="jobDetail" ref="emailJobDetail"/>
            <property name="cronExpression" value="*/5 * * ? * *" />
        </bean>
    
        <!--4.调度-->
        <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="triggers">
                <list>
                    <ref bean="emailTrigger" />
                </list>
            </property>
        </bean>
    </beans>

    7.SpringMVC整合集群版Quartz(要求任务对象必须extends QuartzJobBean)

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    <!--集群版-->
        <!--数据源-->
        <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/et2006" />
            <property name="username" value="root" />
            <property name="password" value="etoak" />
        </bean>
    
        <!-- 事务管理器 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
    
        <!-- JobDetailFactoryBean -->
        <bean id="orderJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="name" value="orderJob" />
            <property name="group" value="orderJob" />
            <!--jobClass-->
            <property name="jobClass" value="com.etoak.job.OrderJob" />
            <!--durability:持久化任务-->
            <property name="durability" value="true" />
        </bean>
    
        <!-- CronTriggerFactoryBean -->
        <bean id="orderTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
            <property name="name" value="orderTrigger" />
            <property name="group" value="orderTrigger"/>
            <property name="jobDetail" ref="orderJobDetail" /><!--ref写成了value-->
            <property name="cronExpression" value="0/5 * * * * ?" />
        </bean>
    
        <!-- SchedulerFactoryBean -->
        <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="transactionManager" ref="transactionManager" />
            <!-- 集群配置 -->
            <property name="configLocation" value="classpath:quartz.properties" />
            <property name="triggers">
                <list>
                    <ref bean="orderTrigger" />
                </list>
            </property>
            <!--第一种-->
            <property name="applicationContextSchedulerContextKey" value="delete" />
            <!--第二种-->
            <property name="jobFactory" ref="mvcJobFactory" />
        </bean>
    </beans>
    ================================两种整合用到的依赖===============================================
    <?xml version="1.0" encoding="UTF-8"?>

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.etoak.et2006.quartz</groupId>
    <artifactId>quartz-springmvc</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>quartz-springmvc Maven Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
    <!-- javax.servlet-api -->
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
    </dependency>

    <!-- spring-webmvc -->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.6.RELEASE</version>
    </dependency>

    <!-- spring-context-support -->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.2.6.RELEASE</version>
    </dependency>

    <!-- spring-jdbc -->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.6.RELEASE</version>
    </dependency>

    <!-- jackson-databind -->
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.3</version>
    </dependency>

    <!-- logback-classic -->
    <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
    </dependency>

    <!-- quartz -->
    <dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
    </dependency>

    <!-- mysql -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.46</version>
    </dependency>
    </dependencies>

    <build>
    <finalName>quartz-springmvc</finalName>
    </build>
    </project>
    ==============================web.xml===================================================
    <!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd" >

    <web-app>
    <!-- spring Root容器(父容器) -->
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-root.xml</param-value>
    </context-param>
    <!-- POST请求编码过滤器 -->
    <filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener><!--监听器--><!--webapp爆红因为违反了dtd规范(标签顺序问题)-->
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 前端控制器 -->
    <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
    </web-app>

     8.springBoot整合Quartz

    8.1
    /*
    * * 配置单机版的Quartz任务 * */ //@Configuration:测试Job/resume重新启动方法时需要把这个注释掉 // 标识这是一个spring容器 public class StandaloneConfig { @Autowired EmailJob emailJob; @Bean(name = "emailJobDetail") public MethodInvokingJobDetailFactoryBean emailJobDetail(){ MethodInvokingJobDetailFactoryBean factoryBean = new MethodInvokingJobDetailFactoryBean(); factoryBean.setName("emailJob"); factoryBean.setGroup("emailJob"); factoryBean.setTargetObject(this.emailJob); factoryBean.setTargetMethod("send"); return factoryBean; } @Bean public CronTriggerFactoryBean emailTrigger(){ CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean(); factoryBean.setName("emailTrigger"); factoryBean.setGroup("emailTrigger"); factoryBean.setJobDetail(this.emailJobDetail().getObject()); factoryBean.setCronExpression("0/5 * * * * ?"); return factoryBean; } @Bean public SchedulerFactoryBean scheduler(){ SchedulerFactoryBean factoryBean = new SchedulerFactoryBean(); factoryBean.setTriggers(this.emailTrigger().getObject()); return factoryBean; } }
    8.2
    /**
     * 集群配置
     *
     * 数据源
     * 事务管理器
     *JobDetailFactoryBean
     *CronTriggerFactoryBean
     *SchedulerFactoryBean
     */
    @Configuration
    public class ClusterConfig {
        /*注入数据源*/
        @Autowired
        DataSource dataSource;
        /*事务管理器*/
        @Bean
        public PlatformTransactionManager transactionManager(){
            return new DataSourceTransactionManager(this.dataSource);
        }
    
        @Bean
        public JobDetailFactoryBean orderJobDetail(){
            JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
            factoryBean.setName("orderJob");
            factoryBean.setGroup("orderJob");
            factoryBean.setJobClass(OrderJob.class);
            factoryBean.setDurability(true);//持久化
            return factoryBean;
        }
    
        @Bean
        public CronTriggerFactoryBean orderTrigger(){
            CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
            factoryBean.setName("orderTrigger");
            factoryBean.setGroup("orderTrigger");
            factoryBean.setJobDetail(this.orderJobDetail().getObject());
            factoryBean.setCronExpression("0/5 * * * * ?");
            return factoryBean;
        }
    
        @Autowired
        MvcJobFactoryBean mvcJobFactoryBean;//第二种方法,其实就是把job注入到了spring容器里;
        //而第一种则是得到spring容器,通过spring容器得到OrderService.class这个Bean
    
        @Bean
        public SchedulerFactoryBean Scheduler(//方法名不能一样,方法名相当于id,@Bean后边参数可以取别名
                /*类型重复可以用这个注解指定用哪个*/
                @Qualifier("transactionManager") PlatformTransactionManager transactionManager
        ){
            SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
            factoryBean.setDataSource(this.dataSource);
            //factoryBean.setTransactionManager(transactionManager);
            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource resource = resolver.getResource("classpath:quartz.properties");
            factoryBean.setConfigLocation(resource);
            factoryBean.setTriggers(this.orderTrigger().getObject());
    
            factoryBean.setApplicationContextSchedulerContextKey("spring");//第一种
            factoryBean.setJobFactory(this.mvcJobFactoryBean);//第二种
            return factoryBean;
        }
    }
    8.3解决集群中的Quartz任务无法使用Spring Bean的问题
    第一种:
    使用applicationContextSchedulerContextKey属性
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { Scheduler scheduler = jobExecutionContext.getScheduler();//第一种 try { SchedulerContext context = scheduler.getContext(); ApplicationContext ioc = (ApplicationContext) context.get("spring"); OrderService orderService = ioc.getBean(OrderService.class);*//*context.get("spring")参数写错,所以ioc为空,orderService也为空*//* orderService.delOrder(); } catch (SchedulerException e) { e.printStackTrace(); } System.out.println("删除超时订单"); }

    第二种:继承SpringBeanJobFactory
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    orderService.delOrder();
    }
    @Component
    public class MvcJobFactoryBean extends SpringBeanJobFactory {
    @Autowired
    AutowireCapableBeanFactory ioc;
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {//第二种

    Object job = super.createJobInstance(bundle);//创建job任务
    ioc.autowireBean(job);//把任务重新注入spring容器中
    return job;
    }
    }

    ===============================================================================================
    @Bean
    public SchedulerFactoryBean Scheduler(//方法名不能一样,方法名相当于id,@Bean后边参数可以取别名
    /*类型重复可以用这个注解指定用哪个*/
    @Qualifier("transactionManager") PlatformTransactionManager transactionManager
    ){
    SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
    factoryBean.setDataSource(this.dataSource);
    //factoryBean.setTransactionManager(transactionManager);
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    Resource resource = resolver.getResource("classpath:quartz.properties");
    factoryBean.setConfigLocation(resource);
    factoryBean.setTriggers(this.orderTrigger().getObject());

    factoryBean.setApplicationContextSchedulerContextKey("spring");//第一种
    factoryBean.setJobFactory(this.mvcJobFactoryBean);//第二种
    return factoryBean;
    }

    8.4测试暂停/重新运行/创建任务的方法

    @RestController
    @RequestMapping("/job")
    public class JobController {
        @Autowired
        Scheduler scheduler;
    
        @RequestMapping("/pause")//暂停
        public String pause(@RequestParam String name, @RequestParam String group) throws SchedulerException {
            TriggerKey triggerKey = new TriggerKey(name,group);
            if(!scheduler.checkExists(triggerKey)){
                return "任务不存在";
            }
            scheduler.pauseTrigger(triggerKey);
            return "success";
        }
        @RequestMapping("/resume")//重新运行
        public String resume(@RequestParam String name, @RequestParam String group) throws SchedulerException {
            TriggerKey triggerKey = new TriggerKey(name,group);
            if(!scheduler.checkExists(triggerKey)){
                return "任务不存在";
            }
            Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
            if(!Trigger.TriggerState.PAUSED.equals(triggerState)){
                return "任务不是暂停状态";
            }
            scheduler.resumeTrigger(triggerKey);
            return "success";
        }
    
        @RequestMapping("/create")
        public String create(@RequestParam String jobName,
                             @RequestParam String jobGroup,
                             @RequestParam String triggerName,
                             @RequestParam String triggerGroup,
                             @RequestParam String cron) throws ParseException, SchedulerException {
            JobDetailImpl jobDetail = new JobDetailImpl();
            jobDetail.setName(jobName);
            jobDetail.setGroup(jobGroup);
            jobDetail.setJobClass(SmsJob.class);
            CronTriggerImpl cronTrigger = new CronTriggerImpl();
            cronTrigger.setName(triggerName);
            cronTrigger.setGroup(triggerGroup);
            cronTrigger.setCronExpression(cron);
            scheduler.scheduleJob(jobDetail,cronTrigger);
            return "success";
    
    
        }
    
    }

  • 相关阅读:
    C# WinForm API 改进单实例运行
    CF1310D Tourism [随机化]
    CF1311E Construct the Binary Tree
    [IOI2018] werewolf 狼人 [kruskal重构树+主席树]
    #6029. 「雅礼集训 2017 Day1」市场 [线段树]
    P5840 [COCI2015]Divljak [AC自动机,链并]
    CF547E Mike and Friends [AC自动机,离线树状数组]
    P5112 FZOUTSY
    CF 150E Freezing with Style [长链剖分,线段树]
    CF1230E Kamil and Making a Stream
  • 原文地址:https://www.cnblogs.com/liuqingzhong/p/14146073.html
Copyright © 2011-2022 走看看