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";


    }

}

 

 

 

posted @ 2020-12-16 20:35  zhong12138  阅读(392)  评论(0编辑  收藏  举报