quartz(开源项目)

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.3.2。

Quartz框架-冯金伟博客园

1.1. Quartz开发步骤说明

1)创建任务 – Job     你要干什么?

2)创建触发器-Trigger  要什么时候做?

3)创建任务调度-Scheduler  什么时候干什么?

1.2. 创建Quartz的Java应用

1.2.1.   导入quartz的坐标

 <dependencies>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.3.2</version>
        </dependency>
    </dependencies>

1.2.2.   定义Job对象

/**
 * 自定义Job
 * @author lenovo
 *
 */
public class TestJob implements Job{

    //execute:一旦任务触发,就会执行此方法
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("任务被触发:"+sdf.format(new Date()));
    }

}

1.2.3.   编写任务调用测试类

Quartz分内简单触发器和日历触发:

简单触发器(SimpleTrigger):主要完成固定重复地任务(按照秒,分,小时)来重复。(例如,每隔30分钟做事件)

日历触发器(CronTrigger): 主要可以按照日历的形式进行重复地任务。(例如:每个星期的一,三,五晚上12点做事情)(常用)

1.2.3.1.       编写简单触发器版本

/**
 * 简单触发器案例
 * @author lenovo
 *
 */
public class SimpleTriggerDemo {

    
    public static void main(String[] args) throws Exception {
        //1)创建任务 - Job     你要干什么?
        JobDetail job = JobBuilder
                    .newJob(TestJob.class)
                    .build();
        
        //2)创建触发器-Trigger  要什么时候做?
        Trigger trigger = TriggerBuilder
                            .newTrigger()
                            .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3))
                            .build();
        //3)创建任务调度-Scheduler  什么时候干什么?
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        //建立job和trigger的关系
        scheduler.scheduleJob(job, trigger);
        
        //4)启动任务
        scheduler.start();
    }
    
}

1.3. 创建CronTrgger日历触发器(比较常用)

按照日历规则进行重复。例如 每个1,3,5进行重复。

/**
 * 日历触发器案例
 *
 */
public class CronTriggerDemo {
    
    public static void main(String[] args) throws Exception {
        //1)创建任务 - Job     你要干什么?
        JobDetail job = JobBuilder
                    .newJob(TestJob.class)
                    .build();
        
        //2)创建触发器-Trigger  要什么时候做?
        Trigger trigger = TriggerBuilder
                            .newTrigger()
                            //传入cron表达式(日历表达式)
                            .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *"))
                            .build();
        //3)创建任务调度-Scheduler  什么时候干什么?
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        //建立job和trigger的关系
        scheduler.scheduleJob(job, trigger);
        
        //4)启动任务
        scheduler.start();
    }
    
}

1.4. cron表达式的语法

CronScheduleBuilder.cronSchedule("0/5 * * * * ? *")

Quartz框架-冯金伟博客园

 Quartz框架-冯金伟博客园

Quartz框架-冯金伟博客园

2.   Spring整合Quartz框架

2.1. 导入quartz和spring的坐标

quartz的坐标:

<!-- quartz任务调度 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.2</version>
</dependency>

spring的坐标:

spring整合quartz的API的spring-context-support

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

2.2. 编写Job任务类

/**
 * 自定义Job
 * @author lenovo
 *
 */
public class TestJob implements Job{

    //execute:一旦任务触发,就会执行此方法
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("任务被触发:"+sdf.format(new Date()));
    }

}

2.3. 编写applicationContext-quartz.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- Spring整合Quartz -->
    <!-- 1.创建JobDetail -->
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- 关联我们的Job类 -->
        <property name="jobClass" value="com.fyc.bos.jobs.TestJob"/>
    </bean>

    <!-- 2.创建Trigger:SimpleTriiger -->
    <bean id="trigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
        <!-- 关联JobDetail -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- 间隔时间 (毫秒)-->
        <property name="repeatInterval" value="3000"></property>
        <!-- 重复次数 -->
        <property name="repeatCount" value="4"></property>
    </bean>
    
    
    <!-- 3.创建Scheduler -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!-- 关联trigger -->
        <property name="triggers">
            <list>
                <ref bean="trigger"/>
            </list>
        </property>
    </bean>    
    
</beans>

导入xml:

<import resource="classpath:applicationContext-quartz.xml"/>

2.4. CronTrigger配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- Spring整合Quartz -->
    <!-- 1.创建JobDetail -->
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- 关联我们的Job类 -->
        <property name="jobClass" value="com.fyc.bos.jobs.TestJob"/>
    </bean>

    <!-- 2.创建Trigger:SimpleTriiger -->
    <bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 关联JobDetail -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- cron表达式 -->
        <property name="cronExpression" value="0/5 * * * * ? *"/>
    </bean>
    
    
    <!-- 3.创建Scheduler -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!-- 关联trigger -->
        <property name="triggers">
            <list>
                <ref bean="trigger"/>
            </list>
        </property>
    </bean>    
    
</beans>

 我的实际项目中的使用

导入的maven依赖

 <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.3.2</version>
        </dependency>
//其它的依赖略

要触发的实际执行的类

这里是根据现在的时间和数据库的实际比较进行的跟新操作。后面的逻辑代码就不贴出了。

public class PromotionJob implements Job {
        @Resource
        private PromotionService promotionService;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //结束时间是否小于系统时间,如果是的话,自动更新status,改为0。
        //System.out.println("PromotionJob任务被触发...");
        promotionService.updateStatus(new Date());
    }
}

配置信息

applicationContext-quartz.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- 关联我们的Job类 -->
        <property name="jobClass" value="com.fyc.bos.jobs.PromotionJob"/>
        <!-- 2.创建Trigger:SimpleTriiger -->
    </bean>
  
    <!-- 2.创建Trigger:SimpleTriiger -->
    <bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 关联JobDetail -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- cron表达式 5秒测试一次-->
        <property name="cronExpression" value="0/5 * * * * ? *"/>
    </bean>

    <!-- 3.创建Scheduler -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!-- 覆盖setJobFactory ,使用我们自定义的JobFactory-->
        <property name="jobFactory" ref="jobFactory"/>
        <!-- 关联trigger -->
        <property name="triggers">
            <list>
                <ref bean="trigger"/>
            </list>
        </property>
    </bean>

</beans>

记得把这份配置导入到spring的主配置中

<import resource="applicationContext-quartz.xml"/>

上面的配置我由于是先测试使用了每五秒做为一次更新。这个日历更新的频率要根据你实际的项目需求去修改

上面的<property name="jobFactory" ref="jobFactory"/>没有添加这个自己注入到的spring对象会出现无法注入PromotionService对象。

在Job对象无法注入Spring对象的问题

原因:Spring框架整合了quartz整合,在创建JobDetail对象的过程中,使用AdapterJobFactory的createJobInstance这个方法去创建JobDetail对象的:

 

通过查看源码,我们发现Spring在创建JobDetail只是用了反射代码直接创建了对象,而没有把该对象放入Spring的IOC容器管理,所以无法在该对象中注入其他Spring对象。

解决办法:手动把JobDetail对象放入SpringIOC容器中。

设计一个JobFactory:

/*
 * 自定义JobFactory对象,重写createJobInstance方法
 */
@Component
public class MyJobFactory extends AdaptableJobFactory {

    @Resource
    private AutowireCapableBeanFactory factory;
    
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        //调用父类的原有的方法创建JobDetail对象
        Object jobDetail = super.createJobInstance(bundle);
        //把JobDetail放入SpringIOC容器中管理
        factory.autowireBean(jobDetail);
        return jobDetail;
    }
}