spring-boot-quartz, 依赖spring-boot-parent

Posted 沧海一滴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring-boot-quartz, 依赖spring-boot-parent相关的知识,希望对你有一定的参考价值。

 

 /** 
  *  
        state的值代表该任务触发器的状态: 
        STATE_BLOCKED   4 // 运行 
        STATE_COMPLETE  2  //完成那一刻,不过一般不用这个判断Job状态 
        STATE_ERROR     3  // 错误 
        STATE_NONE  -1      //未知 
        STATE_NORMAL    0   //正常无任务,用这个判断Job是否在运行 
        STATE_PAUSED    1   //暂停状态 
 */  
import java.util.Date;  
  
import org.quartz.CronTrigger;  
import org.quartz.JobDetail;  
import org.quartz.Scheduler;  
import org.quartz.SchedulerException;  
import org.quartz.SchedulerFactory;  
import org.quartz.SimpleTrigger;  
import org.quartz.Trigger;  
import org.quartz.impl.StdScheduler;  
import org.quartz.impl.StdSchedulerFactory;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.springframework.context.ApplicationContext;  
import org.springframework.scheduling.quartz.SchedulerFactoryBean;  
  
import cn.wa8.qweb.extract.action.Extract2DB;  
public class SimpleRun {  
  
    private static Logger log = LoggerFactory.getLogger(SimpleRun.class);  
  
    public void run() throws Exception {  
        SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();  
        Scheduler sched = schedFact.getScheduler();  
        JobDetail jobDetail = new JobDetail("myJob",null,SimpleJob.class);  
        SimpleTrigger trigger = new SimpleTrigger("myTrigger",  
                null,  
                new Date(),  
                null,  
                SimpleTrigger.REPEAT_INDEFINITELY,  
                30L * 1000L);  
          
        sched.scheduleJob(jobDetail, trigger);  
        //sched.addJobListener(new MyTriggerListener());  
        SimpleJob.preDate = new Date();  
        sched.start();  
        System.out.println("starting");  
 /** 
  *  
        state的值代表该任务触发器的状态: 
        STATE_BLOCKED   4 // 运行 
        STATE_COMPLETE  2  //完成那一刻,不过一般不用这个判断Job状态 
        STATE_ERROR     3  // 错误 
        STATE_NONE  -1      //未知 
        STATE_NORMAL    0   //正常无任务,用这个判断Job是否在运行 
        STATE_PAUSED    1   //暂停状态 
 */  
    while (true){  
        if(4 == sched.getTriggerState("myTrigger", null)){  
            System.out.println("running");  
        }else if(0 == sched.getTriggerState("myTrigger", null)){  
            System.out.println("ending");  
        }else {  
            System.out.println("error state:"+sched.getTriggerState("myTrigger", null));  
        }  
        try {  
            Thread.sleep(5*1000);  
        } catch (Exception e) {  
            // TODO: handle exception  
        }  
    }  
}  
  
    public static void main(String[] args)  {  
          
        SimpleRun simpleRun = new SimpleRun();  
          
        try {  
            simpleRun.run();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}  

 

 

import java.util.Date;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
  
import cn.wa8.qweb.extract.action.Extract2DB;  
  
import org.quartz.Job;  
import org.quartz.JobExecutionContext;  
import org.quartz.JobExecutionException;  
import org.quartz.StatefulJob;  
/*Extract2DB extract2db = new Extract2DB(); 
    extract2db.CommonBaseExtract();*/  
  
public class SimpleJob  implements StatefulJob{  
    public static Date preDate ;  
    public void execute(JobExecutionContext arg0) throws JobExecutionException {  
        System.out.println("into Job");  
        Date currentDate = new Date();  
        Long s = (currentDate.getTime()-preDate.getTime())/1000;  
        try {  
            Thread.sleep(10*1000);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        System.out.println(s);  
        System.out.println("leave Job:"+Thread.currentThread().toString());  
        preDate =currentDate;  
    }  
  
}  

http://blog.csdn.net/u010666884/article/details/51842610




都是执行时间大于间隔时间才会出现的情况,实际做了测试和http://blog.sina.com.cn/s/blog_56d8ea900100cecq.html第2点有点不符,记录如下:

第一种情况:misfire设置时间为600秒;任务每隔2分钟执行一次;任务执行时间为3分钟;
上次执行时间    下次执行时间    状态        解释
20:23:04        20:25:04        正在执行    任务实际要执行到20:26:04,推后两分钟是20:28:04

 

时间到了20:26:04。日志变更为:

20:25:04        20:27:04        正在执行    任务实际要执行的20:29:04,推后两分钟是20:31:04

 

时间到了20:29:04,日志变更为:

20:27:04        20:29:04  

连续三次发现,实际开始的时间减去应该开始的时间差是递增的;上次执行和下次执行时间反映的实际情况都是不准确的,而且会出现下次执行时间小于当前时间的情况。

注意:持续执行的到 实际启动时间 减去 应该开始时间 大于等于misfire时间;奇怪的是,不是开始参考第二种情况继续执行,而是最后一次执行后即开始长时间等待,而且上次以及下次开始时间也不更新,保持原样;直到实际启动时间+misfire时间 时刻开始继续执行,并且更新上次以及下次开始时间,再开始一个上述周期。

第二种情况:misfire设置时间为6秒,任务每隔2分钟执行一次,任务执行时间为3分钟:

上次执行时间    下次执行时间    状态        解释
18:08:12        18:10:12        正在执行    任务实际要执行到18:11:12,推后两分钟是18:13:12

 

时间到了18:11:12,日志变更为:

18:08:12        18:10:12        等待        超出misfire时间;任务还没有更新状态
18:08:12        18:12:12        等待        是18:12:12,而不是18:13:12。

算法描述如下:

本次任务应该开始时间为18:10:12,应该结束时间为18:12:12;实际启动时间为18:11:12;实际启动后结束时间为18:13:12;实际启动时间减去应该开始时间超出了misfire,所以状态为等待,即本次任务不执行,从而上次执行时间不变;
计算下次执行时间:当前时间为18:11:12(或者一个稍微大于该值的值),拿应该结束时间以及实际启动后结束时间和当前时间比较,取当前时间往后的最小值作为下次任务启动时间。(算法兼容下面第2点说法)
18:12:12 18:14:12 正在执行

其他引用:
org.quartz.jobStore.misfireThreshold = 60000 #60秒 默认值
那么执行第一次作业是在10:01秒,这时会设定下一次的执行时间为10:02秒,要等一个作业执行完之后才有可用线程,大概要在10:11秒才能执行前面安排的应该在10:02执行的作业,这时就会用到misfireThreshold, 因为10:11与10:02之间的差值小于6000,所以执行该作业,并以10:02为基准设置下一次执行时间为10:03,这样造成每次实际执行时间与安排时间错位
如果 org.quartz.jobStore.misfireThreshold = 6000 #秒
同样,在10:11计划执行安排在10:02的作业,发现10:11与10:02之间的差值小于6000,那么直接跳过该作业,执行本应在当前时间执行的 作业,这时候会以10:11为基准设定下次作业执行时间为10:12(状态此段区间内一直是等待,只是更改了下次作业时间)

其他情况:
quartz有个全局的参数misfireThreshold设置可以允许的超时时间,超过了就不执行,未超过就执行。
比如设置了misfireThreshold=30分钟,如果一个任务定时在10:30执行,但在10:29服务器挂了,在10:50启动,虽然任务超时了21分钟,但小于misfireThreshold,所以还是可以执行
而如果服务器11:10才启动,那就misfire了。

对于周期性的任务,如果有misfire的情况出现,则会自动更新CronTrigger的时间周期
默认情况下会在当前时间马上执行前一个被misfire的任务
而如果设置MISFIRE_INSTRUCTION_DO_NOTHING,则不对misfire的任务做特殊处理,只从当前时间之后的下一次正常调度时间开始执行

http://blog.sina.com.cn/s/blog_56d8ea900101d2mh.html

 

http://www.quartz-scheduler.org/documentation/quartz-2.1.x/quick-start.html

spring-boot-quartz, 依赖spring-boot-parent

image

application.properties

# IDENTITY (ContextIdApplicationContextInitializer)
spring.application.index=WebQuartz.v1.1
spring.application.name=WebQuartz

#Server
server.port=80
server.jsp-servlet.class-name=org.apache.jasper.servlet.JspServlet

security.basic.enabled=false
management.security.enabled=false

#MVC
spring.mvc.view.prefix=/WEB-INF/views/
spring.resources.static-locations=classpath:/static/

security.basic.enabled=false
management.security.enabled=false

#LOG
logging.config=classpath:log4j2.xml

configuration

@Configuration
public class QuartzConfig {

    @Bean
    public Scheduler scheduler() throws IOException, SchedulerException {
        SchedulerFactory schedulerFactory = new StdSchedulerFactory(quartzProperties());
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();
        return scheduler;
    }

    /**
     * 设置quartz属性
     * @throws IOException
     * 2016年10月8日下午2:39:05
     */
    public Properties quartzProperties() throws IOException {
        Properties prop = new Properties();
        prop.put("quartz.scheduler.instanceName", "ServerScheduler");
        prop.put("org.quartz.scheduler.instanceId", "AUTO");
        prop.put("org.quartz.scheduler.skipUpdateCheck", "true");
        prop.put("org.quartz.scheduler.instanceId", "NON_CLUSTERED");
        prop.put("org.quartz.scheduler.jobFactory.class", "org.quartz.simpl.SimpleJobFactory");
        prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
        prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
        prop.put("org.quartz.jobStore.dataSource", "quartzDataSource");
        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
        prop.put("org.quartz.jobStore.isClustered", "true");
        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        prop.put("org.quartz.threadPool.threadCount", "5");

        prop.put("org.quartz.dataSource.quartzDataSource.driver", "com.mysql.jdbc.Driver");
        prop.put("org.quartz.dataSource.quartzDataSource.URL", "jdbc:mysql://localhost:3306/demo-schema");
        prop.put("org.quartz.dataSource.quartzDataSource.user", "root");
        prop.put("org.quartz.dataSource.quartzDataSource.password", "123456");
        prop.put("org.quartz.dataSource.quartzDataSource.maxConnections", "10");
        return prop;
    }
}

JS

@Service
public class TaskServiceImpl {
    private Logger logger = LogManager.getLogger(getClass());
    @Autowired
    private Scheduler scheduler;

    /**
     * 所有任务列表
     * 2016年10月9日上午11:16:59
     */
    public List<TaskInfo> list(){
        List<TaskInfo> list = new ArrayList<>();

        try {
            for(String groupJob: scheduler.getJobGroupNames()){
                for(JobKey jobKey: scheduler.getJobKeys(GroupMatcher.<JobKey>groupEquals(groupJob))){
                    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                    for (Trigger trigger: triggers) {
                        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                        JobDetail jobDetail = scheduler.getJobDetail(jobKey);

                        String cronExpression = "", createTime = "";

                        if (trigger instanceof CronTrigger) {
                            CronTrigger cronTrigger = (CronTrigger) trigger;
                            cronExpression = cronTrigger.getCronExpression();
                            createTime = cronTrigger.getDescription();
                        }
                        TaskInfo info = new TaskInfo();
                        info.setJobName(jobKey.getName());
                        info.setJobGroup(jobKey.getGroup());
                        info.setJobDescription(jobDetail.getDescription());
                        info.setJobStatus(triggerState.name());
                        info.setCronExpression(cronExpression);
                        info.setCreateTime(createTime);
                        list.add(info);
                    }                   
                }
            }           
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * 保存定时任务
     * @param info
     * 2016年10月9日上午11:30:40
     */
    @SuppressWarnings("unchecked")
    public void addJob(TaskInfo info) {
        String jobName = info.getJobName(), 
               jobGroup = info.getJobGroup(), 
               cronExpression = info.getCronExpression(),
               jobDescription = info.getJobDescription(),
               createTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        try {
            if (checkExists(jobName, jobGroup)) {
                logger.info("===> AddJob fail, job already exist, jobGroup:{}, jobName:{}", jobGroup, jobName);
                throw new ServiceException(String.format("Job已经存在, jobName:{%s},jobGroup:{%s}", jobName, jobGroup));
            }

            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);

            CronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withDescription(createTime).withSchedule(schedBuilder).build();


            Class<? extends Job> clazz = (Class<? extends Job>)Class.forName(jobName);
            JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobKey).withDescription(jobDescription).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException | ClassNotFoundException e) {
            throw new ServiceException("类名不存在或执行表达式错误");
        }
    }

    /**
     * 修改定时任务
     * @param info
     * 2016年10月9日下午2:20:07
     */
    public void edit(TaskInfo info) {
        String jobName = info.getJobName(), 
               jobGroup = info.getJobGroup(), 
               cronExpression = info.getCronExpression(),
               jobDescription = info.getJobDescription(),
               createTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        try {
            if (!checkExists(jobName, jobGroup)) {
                throw new ServiceException(String.format("Job不存在, jobName:{%s},jobGroup:{%s}", jobName, jobGroup));
            }
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            JobKey jobKey = new JobKey(jobName, jobGroup);
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
            CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withDescription(createTime).withSchedule(cronScheduleBuilder).build();

            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            jobDetail.getJobBuilder().withDescription(jobDescription);
            HashSet<Trigger> triggerSet = new HashSet<>();
            triggerSet.add(cronTrigger);

            scheduler.scheduleJob(jobDetail, triggerSet, true);
        } catch (SchedulerException e) {
            throw new ServiceException("类名不存在或执行表达式错误");
        }
    }

    /**
     * 删除定时任务
     * @param jobName
     * @param jobGroup
     * 2016年10月9日下午1:51:12
     */
    public void delete(String jobName, String jobGroup){
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        try {
            if (checkExists(jobName, jobGroup)) {
                scheduler.pauseTrigger(triggerKey);
                scheduler.unscheduleJob(triggerKey);
                logger.info("===> delete, triggerKey:{}", triggerKey);
            }
        } catch (SchedulerException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 验证是否存在
     * @param jobName
     * @param jobGroup
     * @throws SchedulerException
     * 2016年10月8日下午5:30:43
     */
    private boolean checkExists(String jobName, String jobGroup) throws SchedulerException{
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        return scheduler.checkExists(triggerKey);
    }
}

 

https://github.com/leelance/spring-boot-all/tree/master/spring-boot-quartz

简单的说调度器就是: 

Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息(Scheduler运行时会执行类A的excute方法),

JobDetail描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息。

Trigger:是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等

Calendar:一个Trigger可以和多个Calendar关联

Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job

SchedulerContext:它类似于ServletContext,保存着Scheduler上下文信息.

JobDataMap : qrtz_job_details表JOB_DATA字段存放了相关数据

 

在前面部分,我们知道Job中定义了实际的业务逻辑,而JobDetail包含Job相关的配置信息。在Quartz中,每次Scheduler执行Job时,在调用其execute()方法之前,它需要先根据JobDetail提供的Job类型创建一个Job class的实例,在任务执行完以后,Job class的实例会被丢弃,Jvm的垃圾回收器会将它们回收。

因此编写Job的具体实现时,需要注意:(1) 它必须具有一个无参数的构造函数;(2) 它不应该有静态数据类型,因为每次Job执行完以后便被回收,因此在多次执行时静态数据没法被维护。

Keep moving,在JobDetail中有这么一个成员JobDataMap,JobDataMap是Java Map接口的具体实现,并添加了一些便利的方法用于存储与读取原生类型数据,里面包含了当Job实例运行时,你希望提供给它的所有数据对象。

可以借助JobDataMap为Job实例提供属性/配置,可以通过它来追踪Job的执行状态等等。对于第一种情况,可以在创建Job时,添加JobDataMap数据,在Job的execute()中获取数据,第二种,则可以在Listener中通过获取JobDataMap中存储的状态数据追踪Job的执行状态。

按例,一个简单的例子:

  1. // 创建Job的实例
  2. JobDetail jobIns = JobBuilder.newJob(SimpleJob.class).withIdentity(
  3. "simpleJob", "group1").usingJobData("domain",
  4. "www.jmatrix.org").usingJobData("rank", "求别提~~~").build();

Job实现:

  1. public void execute(JobExecutionContext context)
  2. throws JobExecutionException {
  3. System.out.println("开始!");
  4.  
  5. //……JobDataMap
  6. JobDataMap dataMap = context.getJobDetail().getJobDataMap();
  7. System.out.println("域名 : "+dataMap.getString("domain"));
  8. System.out.println("排名 : "+dataMap.getString("rank"));
  9.  
  10. System.out.println("结束!");
  11. }

完成了这些工作,还需决定如何存储Job的数据,Quartz提供了JobStore接口来做这件事,如果你决定将Job数据保存在内存中,则可以使用RAMJobStore,它的优点是速度快,缺点是一旦机器挂了,Job相关的数据也丢失了,

如果要采用数据库来存储Job数据,可以使用JobStoreTX或JobStoreCMT,这取决于你采用的事务管理方式,使用RAMJobStore的话配置很简单,只需配置org.quartz.jobStore.class即可,

如果使用数据库存储,则还需要配置
driverDelegate
tablePrefix
dataSource
driverDelegate
一般情况下使用StdJDBCDelegate(MySQL便可使用这个),
特殊的可以使用Quartz提供的相关delegate,请查看jar包,一般命名就说明了一切。
TablePrefix是你的数据库表前缀,创建数据库的sql文件可以在docs\\dbTables目录下找到。
最后的数据源dataSource就有点麻烦,Quartz为用户提供了三种创建dataSource的方式:

  1. 配置相关的数据库属性(driverClass,url,username,password等),让Quartz为你创建dataSource。
  2. 通过jndi使用你应用服务器管理的dataSource。
  3. 通过实现org.quartz.utils.ConnectionProvider定制自己的datasource。

前面两种都是依据datasource的名称为其配置相关的属性,具体有哪些属性可直接参考Quartz的文档。

quartz.properties 配置:

# Main Quartz configuration
#是否跳过联网检查更新
#默认会联网检查是否有更新
org.quartz.scheduler.skipUpdateCheck = true
#调度器的实例名
#可以是你喜欢的任何字符串。它用来在用到多个调度器区分特定的调度器实例
org.quartz.scheduler.instanceName = DatabaseScheduler
#调度器的实例ID
#也允许任何字符串。这个值必须是在所有调度器实例中是唯一的,尤其是在一个集群当中
#如果 Quartz 框架是运行在非集群环境中,那么自动产生的值将会是 NON_CLUSTERED
#假如是在集群环境下使用 Quartz,这个值将会是主机名加上当前的日期和时间。大多情况下,设置为 AUTO 即可
org.quartz.scheduler.instanceId = NON_CLUSTERED
#作业存储方式
#数据库存储
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = quartzDataSource
#org.quartz.dataSource.quartzDataSource.connectionProvider.class = cn.com.quartz.QuartzDataSource
#调度器数据库表前缀
org.quartz.jobStore.tablePrefix = QRTZ_
#线程管理类
#Quartz 自带的线程池实现类
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
#处理的线程个数
org.quartz.threadPool.threadCount = 10

#这是项目启动自动到数据库加载调度任务的设置,但是我没加一样可以自动初始化,设置false无效
# org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
# 作业存储数据库配置: JDBC jobStoreTX
#org.quartz.dataSource.quartzDataSource.driver = com.microsoft.sqlserver.jdbc.SQLServerDriver
#org.quartz.dataSource.quartzDataSource.URL = jdbc:sqlserver://192.168.1.69:1433;database=DGWEB
#org.quartz.dataSource.quartzDataSource.user = sa
#org.quartz.dataSource.quartzDataSource.password = matech
#org.quartz.dataSource.quartzDataSource.driver = oracle.jdbc.driver.OracleDriver
#org.quartz.dataSource.quartzDataSource.URL = jdbc:oracle:thin:@127.0.0.1:1521:MATECH
#org.quartz.dataSource.quartzDataSource.user = matech
#org.quartz.dataSource.quartzDataSource.password = matech


#org.quartz.dataSource.quartzDataSource.driver = com.mysql.jdbc.Driver
#org.quartz.dataSource.quartzDataSource.URL = jdbc:mysql://127.0.0.1:3306/asdb
#org.quartz.dataSource.quartzDataSource.user = root
#org.quartz.dataSource.quartzDataSource.password = 123


org.quartz.dataSource.quartzDataSource.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.quartzDataSource.URL = jdbc:mysql://183.60.183.47:8098/asdb
org.quartz.dataSource.quartzDataSource.user = xoops_root
org.quartz.dataSource.quartzDataSource.password = 654321
# 最大的数据库链接数:推荐 threadCount size + 3
#org.quartz.dataSource.quartzDataSource.maxConnections = 8


#在超过它的下次触发时多少毫秒才算是错过触发 
org.quartz.jobStore.misfireThreshold = 60000
#同一时刻能处理错过触发 Trigger 的最大数量
org.quartz.jobStore.maxMisfiresToHandleAtATime = 10

 

http://blog.csdn.net/fupengyao/article/details/51645897

 

 

由于项目使用spring-boot框架,其框架是为了实现零配置文件去做开发的理念,所以在项目中集成Quartz任务调度并不像spring那样直接配置XML.

首先项目需要用到的jar包:

 

[html] view plain copy
 
  1. <dependency>  
  2.             <groupId>org.springframework</groupId>  
  3.             <artifactId>spring-context-support</artifactId>  
  4.             <version>4.1.6.RELEASE</version>  
  5.         </dependency>  
  6. <dependency>  
  7.             <groupId>org.quartz-scheduler</groupId>  
  8.             <artifactId>quartz</artifactId>  
  9.             <version>2.2.1</version>  
  10.         </dependency>  


交给spring管理的bean,代码如下

 

 

[java] view plain copy
 
  1. package com.xxx;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.mybatis.spring.annotation.MapperScan;  
  6. import org.quartz.JobDetail;  
  7. import org.quartz.Trigger;  
  8. import org.quartz.spi.JobFactory;  
  9. import org.springframework.beans.factory.annotation.Qualifier;  
  10. import org.springframework.beans.factory.annotation.Value;  
  11. import org.springframework.boot.autoconfigure.EnableAutoConfiguration;  
  12. import org.springframework.context.ApplicationContext;  
  13. import org.springframework.context.annotation.Bean;  
  14. import org.springframework.context.annotation.ComponentScan;  
  15. import org.springframework.context.annotation.ComponentScan.Filter;  
  16. import org.springframework.context.annotation.Configuration;  
  17. import org.springframework.context.annotation.FilterType;  
  18. import org.springframework.scheduling.annotation.EnableScheduling;  
  19. import org.springframework.scheduling.quartz.CronTriggerFactoryBean;  
  20. import org.springframework.scheduling.quartz.JobDetailFactoryBean;  
  21. import org.springframework.scheduling.quartz.SchedulerFactoryBean;  
  22. import org.springframework.test.context.ContextConfiguration;  
  23. import org.springframework.test.context.web.WebAppConfiguration;  
  24. import org.springframework.transaction.annotation.EnableTransactionManagement;  
  25.   
  26. import com.xxx.base.BaseWebAppConfig;  
  27. import com.xxx.cars.quartz.AutowiringSpringBeanJobFactory;  
  28. import com.xxx.cars.quartz.SampleJob;  
  29.   
  30. @Configuration  
  31. @EnableScheduling  
  32. @ContextConfiguration  
  33. @WebAppConfiguration  
  34. @ComponentScan(basePackages = { "com.xxx" }, excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Configuration.class) })  
  35. @MapperScan("com.xxx.cars.persistence")  
  36. @EnableTransactionManagement  
  37. @EnableAutoConfiguration  
  38. public class WebAppConfig extends BaseWebAppConfig {  
  39.     /** 
  40.      * 配置拦截器 
  41.      *  
  42.      * @author jodie 
  43.      * @param registry 
  44.      */  
  45. //  public void addInterceptors(InterceptorRegistry registry) {  
  46. //      registry.addInterceptor(new UserSecurityInterceptor()).addPathPatterns(  
  47. //              "/**");  
  48. //  }  
  49.       
  50.      @Bean  
  51.         public JobFactory jobFactory(ApplicationContext applicationContext) {  
  52.             AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();  
  53.             jobFactory.setApplicationContext(applicationContext);  
  54.             return jobFactory;  
  55.         }  
  56.   
  57.         /**调度工厂bean  
  58.          * @param jobFactory  
  59.          * @param sampleJobTrigger  
  60.          * @return  
  61.          * @author LDX  
  62.          * @throws IOException  
  63.          */  
  64.         @Bean  
  65.         public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory,  
  66.                                                          @Qualifier("cronJobTrigger") Trigger cronJobTrigger) throws IOException {  
  67.             SchedulerFactoryBean factory = new SchedulerFactoryBean();  
  68.             // this allows to update triggers in DB when updating settings in config file:  
  69.             //用于quartz集群,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了  
  70.             factory.setOverwriteExistingJobs(true);  
  71.           //用于quartz集群,加载quartz数据源  
  72. //          factory.setDataSource(dataSource);  
  73.             factory.setJobFactory(jobFactory);  
  74.             //QuartzScheduler 延时启动,应用启动完20秒后 QuartzScheduler 再启动  
  75.             factory.setStartupDelay(20);  
  76.           //用于quartz集群,加载quartz数据源配置  
  77. //          factory.setQuartzProperties(quartzProperties());  
  78.             //注册触发器  
  79.             factory.setTriggers(cronJobTrigger);  
  80.   
  81.             return factory;  
  82.         }  
  83.   
  84.         /**加载quartz数据源配置,quartz集群时用到 
  85.          * @return 
  86.          * @author LDX 
  87.          * @throws IOException 
  88.          */  
  89. //      @Bean  
  90. //      public Properties quartzProperties() throws IOException {  
  91. //          PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();  
  92. //          propertiesFactoryBean.se

    以上是关于spring-boot-quartz, 依赖spring-boot-parent的主要内容,如果未能解决你的问题,请参考以下文章

    Spring 如何解决循环依赖的问题

    Spring依赖注入:注解注入总结

    logback的使用和原理

    SpringBoot导入mail依赖报错

    摇篮 | Spring boot 依赖不排除

    springboot-dubbo