Spring+Quarze 案例

前言

我们现在做的web项目有许多需求是需要用到定时任务的,quarze给我们带来了很多方便,如何使用quarze去帮助我们调度我们的任务呢?下面给大家分享一下:

项目目的:我们将需要执行的定时任务放进任务表中,应用定时扫描我们的任务,让quarze管理调度我们的任务。

以下代码亲测有效,,也可以直接复用,欢迎各位指正!

 

 

 

pom.xml

<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>mlstudy</groupId>
    <artifactId>mlstudy</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <spring.version>4.3.12.RELEASE</spring.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.29</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.7</version>
        </dependency>
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4.4</version>
        </dependency>

        <!-- spring -->

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <!-- <scope>test</scope> -->
        </dependency>
        <dependency>
            <groupId> org.springframework</groupId>
            <artifactId> spring-context</artifactId>
            <version> ${spring.version}</version>
        </dependency>
        <dependency>
            <groupId> org.springframework</groupId>
            <artifactId> spring-core</artifactId>
            <version> ${spring.version}</version>
        </dependency>
        <dependency>
            <groupId> org.springframework</groupId>
            <artifactId> spring-beans</artifactId>
            <version> ${spring.version}</version>
        </dependency>
        <dependency>
            <groupId> org.springframework</groupId>
            <artifactId> spring-web</artifactId>
            <version> ${spring.version}</version>
        </dependency>
        <dependency>
            <groupId> org.springframework</groupId>
            <artifactId> spring-webmvc </artifactId>
            <version> ${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-support</artifactId>
            <version>2.0.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session</artifactId>
            <version>1.1.0.RELEASE</version>
        </dependency>
        <!-- 数据库及映射 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <!-- quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>

    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

web.xml(别忘记让tomcat去加载我们的配置文件, ContextLoaderListener监听器必须要有哦)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <display-name>mlstudy</display-name>
  
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:/config/application-context.xml
        </param-value>
    </context-param>
    
    <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
</web-app>

 

application-context.xml:

<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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
        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
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd ">

    <!-- 注册 AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor这四个bean -->
    
    <context:annotation-config /> 
    
    <!-- 自动扫描web包 ,将带有注解的类 纳入spring容器管理 。<context:component-scan/>不但启用了对类包进行扫描以实施注释驱动 Bean 定义的功能,同时还启用了注释驱动自动注入的功能(即还隐式地在内部注册了AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor),因此,一定程度上<context:annotation-config />可以注释掉   -->
   
    <context:component-scan base-package="com.flower.job"></context:component-scan> 
    
    <!-- MVC注解支持   mvc:annotation-driven /> 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的,即解决了@Controller注解使用的前提配置-->
   

    <mvc:annotation-driven/> 
   
    <context:property-placeholder location="classpath:/config/jdbc.properties"/>
    
    <!-- 数据源配置 -->
     <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="filters" value="stat"/>
        <property name="maxActive" value="20"/>
        <property name="initialSize" value="1"/>
        <property name="maxWait" value="60000"/>
        <property name="minIdle" value="1"/>
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <property name="minEvictableIdleTimeMillis" value="300000"/>
        <property name="validationQuery" value="SELECT 'x'"/>
        <property name="testWhileIdle" value="true"/>
        <property name="testOnBorrow" value="false"/>
        <property name="testOnReturn" value="false"/>
        <property name="poolPreparedStatements" value="true"/>
        <property name="maxOpenPreparedStatements" value="20"/>
    </bean>
    
    <!--事务就是对一系列的数据库操作进行统一的提交或回滚操作, Spring中也有自己的事务管理机制  -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!-- 配置mybatis核心  创建configurtion对象     SqlSessionFactoryBuilder根据传入的数据流生成Configuration对象,然后根据Configuration对象创建默认的SqlSessionFactory实例-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="configLocation" value="classpath:/config/mapperConfig.xml" /> 
        <property name="dataSource" ref="dataSource" />  
        <property name="mapperLocations" value="classpath:/mapper/*.xml"></property> 
    </bean> 
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.flower.job.dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        </bean> 
    
     <!--     配置quartze系统任务 -->
   <bean id="quartzManagerBean" class="com.flower.job.QuarzeManage">  
        <property name="scheduler" ref="schedulerManager" />  
    </bean>  
    <bean id="quartzManagerJobDetail"  
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
        <property name="targetObject" ref="quartzManagerBean" />  
        <property name="targetMethod" value="execute" />  
        <property name="concurrent" value="false" />  
    </bean>  
   <!--  主定时计划  每隔30秒钟触发一次,每30秒去扫描sys_job表 -->
    <bean id="quartzManagerTrigger"  
        class=" org.springframework.scheduling.quartz.CronTriggerFactoryBean">  
        <property name="jobDetail" ref="quartzManagerJobDetail" />  
          <property name="cronExpression" value="0/30 * * * * ?"/>
    </bean>  
   <!--  总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序    -->
    <bean id="schedulerManager" lazy-init="false" autowire="no"  
        class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
        <property name="triggers">  
            <list>  
                <ref bean="quartzManagerTrigger" />  
            </list>  
        </property>
        <property name="autoStartup" value="true"/>   
    </bean>  

</beans>

 

jdbc.properties(配置数据库连接参数)

jdbc.url=jdbc:mysql://localhost:3306/flower? ?autoReconnect=true&zeroDateTimeBehavior=round&useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=1234

ScheduleJob(实体类)

package com.flower.job.entity;


public class ScheduleJob {
    int id;
    
    String jobName;
    String groupName;
    String cron;
    String className;
    String targetClass;
    String targetMehod;
    public String getJobName() {
        return jobName;
    }
    public void setJobName(String jobName) {
        this.jobName = jobName;
    }
    public String getGroupName() {
        return groupName;
    }
    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }
    public String getCron() {
        return cron;
    }
    public void setCron(String cron) {
        this.cron = cron;
    }
    public String getClassName() {
        return className;
    }
    public void setClassName(String className) {
        this.className = className;
    }
    public String getTargetClass() {
        return targetClass;
    }
    public void setTargetClass(String targetClass) {
        this.targetClass = targetClass;
    }
    public String getTargetMehod() {
        return targetMehod;
    }
    public void setTargetMehod(String targetMehod) {
        this.targetMehod = targetMehod;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}
 

mapperConfig.xml(mybatis配置文件)

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

<!--mybatis打印sql -->

   <!-- <settings>
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings> -->
    <typeAliases>
        <typeAlias alias="JSONObject" type="com.alibaba.fastjson.JSONObject" />
        <typeAlias alias="JSONArray" type="com.alibaba.fastjson.JSONArray" />
        <typeAlias alias="ScheduleJob" type="com.flower.job.entity.ScheduleJob" />
    </typeAliases>

</configuration>

schedulerJob.xml(mapper文件)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.flower.job.dao.ScheduleDao" >

    
    <resultMap id="BaseResultMap" type="ScheduleJob">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="job_name" jdbcType="VARCHAR" property="jobName" />
        <result column="group_name" jdbcType="VARCHAR" property="groupName" />
        <result column="cron" jdbcType="VARCHAR" property="cron" />
        <result column="target_class" jdbcType="VARCHAR" property="targetClass" />
        <result column="target_mehod" jdbcType="VARCHAR" property="targetMehod" />
    </resultMap>

    <select id="findAll"  resultMap="BaseResultMap">
        SELECT * FROM sys_job
    </select>

</mapper>

ScheduleDao(查询dao)

package com.flower.job.dao;
import java.util.List;
import com.flower.job.entity.ScheduleJob;

public interface ScheduleDao {
    List<ScheduleJob> findAll();
}
 

QuarzeManage.java(核心调度类)

package com.flower.job;

import java.util.List;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;

import com.flower.job.dao.ScheduleDao;
import com.flower.job.entity.ScheduleJob;
import com.flower.job.task.Task1;

public class QuarzeManage {
    
    @Autowired
    private ScheduleDao scheduleDao;
    
    //set注入scheduler
    private Scheduler scheduler;
     public Scheduler getScheduler() {
        return scheduler;
    }
    public void setScheduler(Scheduler scheduler) {
        this.scheduler = scheduler;
    }
    
    
    public void execute() {
        List<ScheduleJob> list = scheduleDao.findAll();
        for (ScheduleJob job : list){
            createJob(job);
        }
    }
    
    /**
     * 添加任务
     * @param job
     */
    @SuppressWarnings({ "unchecked", "rawtypes"})
    public void createJob(ScheduleJob job) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getGroupName());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            Class clazz=  Class.forName(job.getTargetClass());
            //不存在,则创建
            if (null == trigger) {
                JobDetail jobDetail = JobBuilder.
                        newJob(clazz).
                        withIdentity(job.getJobName(), job.getGroupName()).
                        build();

                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCron());

                //withIdentity中写jobName和groupName
                trigger = TriggerBuilder.
                        newTrigger().
                        withIdentity(job.getJobName(), job.getGroupName())
                        .withSchedule(scheduleBuilder)
                        .build();
                scheduler.scheduleJob(jobDetail, trigger);
                
            } else {
                modifyJob(job,triggerKey);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 修改任务
     * @param job
     * @param triggerKey
     */
    public void modifyJob(ScheduleJob job,TriggerKey triggerKey){
        try {
            if (null == triggerKey){
                triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getGroupName());
            }
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (!trigger.getCronExpression().equals(job.getCron())){
                // Trigger已存在,那么更新相应的定时设置
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCron());
                // 按新的cronExpression表达式重新构建trigger
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                // 按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        } catch (SchedulerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    /**
     * 移除任务
     */
    public void removeJob(ScheduleJob job){
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getGroupName());
            // 停止触发器
            scheduler.pauseTrigger(triggerKey);
            //移除触发器
            scheduler.unscheduleJob(triggerKey);
            // 删除任务
            scheduler.deleteJob(JobKey.jobKey(job.getJobName(),job.getGroupName()));
        } catch (SchedulerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Task1 (子任务1)

package com.flower.job.task;

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

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class Task1 implements Job{

    @Override
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        System.out.println(df.format(new Date())+":子任务1");
    }
}


Task2(子任务2)

package com.flower.job.task;

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

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class Task2 implements Job{

    @Override
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        System.out.println(df.format(new Date())+":子任务2");
    }

}
 

 

运行结果:

 

spring3.0+,Quarze 2.X搭配

spring3.0-  Quarze 1.X搭配不然会出现:

 

使用Spring配置管理Quartz的时候会遇到下面的异常:

  1. Caused by: java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as super class  

原因是Spring 3.0版本中内置的Quartz版本是<2.0的,在使用最新的Quartz包(>2.0)之后,接口不兼容。

 

解决办法有三种:

 

1.降低Quartz版本,降到1.X去。

2.升级Spring版本到3.1+,根据Spring的建议,将原来的**TriggerBean替换成**TriggerFactoryBean,例如CronTriggerBean 就可以替换成 CronTriggerFactoryBean。替换之后问题解决。

3.如果不在xml配置文件中引用 Spring 3.0 是支持 Quartz2.2.1(目前最新版本),直接在程序中调用即可。

 <!-- 配置quartze系统任务 -->
   <bean id="quartzManagerBean" class="mldemo.lyl.quartze.QuartzeRun">  
        <property name="scheduler" ref="schedulerManager" />  
    </bean>  
    <bean id="quartzManagerJobDetail"  
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
        <property name="targetObject" ref="quartzManagerBean" />  
        <property name="targetMethod" value="execute" />  
        <property name="concurrent" value="false" />  
    </bean>  
    <!-- 主定时计划 -->  
    <bean id="quartzManagerTrigger"  
        class="org.springframework.scheduling.quartz.CronTriggerBean">  
        <property name="jobDetail" ref="quartzManagerJobDetail" />  
           <property name="cronExpression" value="*/5 * * * * ?"/><!-- 每隔5秒钟触发一次 --> 
    </bean>  
    <!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序  -->  
    <bean id="schedulerManager" lazy-init="false" autowire="no"  
        class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
        <property name="triggers">  
            <list>  
                <ref bean="quartzManagerTrigger" />  
            </list>  
        </property>
        <property name="autoStartup" value="true"/>   
    </bean>  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值