Quartz有两种,编程式的和声明式的,编程式的是直接在类中写代码的,声明式的是集成Spring在xml中配置。
一、编程式
例子都是基于Quartz 2.2.1
package com.test.quartz;
import static org.quartz.DateBuilder.newDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;
import java.util.GregorianCalendar;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.calendar.AnnualCalendar;
public class QuartzTest {
public static void main(String[] args) {
try {
//创建scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//定义一个Trigger
Trigger trigger = newTrigger().withIdentity("trigger1", "group1") //定义name/group
.startNow()//一旦加入scheduler,立即生效
.withSchedule(simpleSchedule() //使用SimpleTrigger
.withIntervalInSeconds(1) //每隔一秒执行一次
.repeatForever()) //一直执行,奔腾到老不停歇
.build();
//定义一个JobDetail
JobDetail job = newJob(HelloQuartz.class) //定义Job类为HelloQuartz类,这是真正的执行逻辑所在
.withIdentity("job1", "group1") //定义name/group
.usingJobData("name", "quartz") //定义属性
.build();
//加入这个调度
scheduler.scheduleJob(job, trigger);
//启动之
scheduler.start();
//运行一段时间后关闭
Thread.sleep(10000);
scheduler.shutdown(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.test.quartz;
import java.util.Date;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class HelloQuartz implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDetail detail = context.getJobDetail();
String name = detail.getJobDataMap().getString("name");
System.out.println("say hello to " + name + " at " + new Date());
}
}
这个例子很好的覆盖了Quartz最重要的3个基本要素:
- Scheduler:调度器。所有的调度都是由它控制。
- Trigger: 定义触发的条件。例子中,它的类型是SimpleTrigger,每隔1秒中执行一次(什么是SimpleTrigger下面会有详述)。
- JobDetail & Job: JobDetail 定义的是任务数据,而真正的执行逻辑是在Job中,例子中是HelloQuartz。 为什么设计成JobDetail + Job,不直接使用Job?这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。
二、声明式
先导入jar
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
配置XML文件,记得一定要加载这个xml,我的xml取名叫做spring-context-quartz.xml,是在web.xml中通过通配符形式匹配加载的
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/spring-context*.xml</param-value>
</context-param>
在Spring中使用Quartz有两种方式实现:第一种是任务类继承QuartzJobBean(可传参),第二种则是在配置文件里定义任务类和要执行的方法(不可传参),类和方法仍然是普通类,下面没有注释的是第二种,有注释的是第一种
<!--默认扫描的包路径 -->
<context:component-scan base-package="net.nengmao.backend.vendor.common.utils.quartz" />
<bean id="simpleJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myBean" />
<!-- 任务类中需要执行的方法 -->
<property name="targetMethod" value="printMessage" />
<!-- 上一次未执行完成的,要等待有再执行。 -->
<property name="concurrent" value="false"></property>
</bean>
<!-- <bean id="firstComplexJobDetail"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass"
value="net.nengmao.backend.vendor.common.utils.quartz.FirstScheduledJob" />
<property name="jobDataMap">
<map>
<entry key="anotherBean" value-ref="anotherBean" />
</map>
</property>
<property name="Durability" value="true"/>
</bean>-->
<!-- 距离当前时间一分钟之后执行,之后每隔五分钟执行一次 -->
<bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="simpleJobDetail"/>
<property name="startDelay" value="120000"/>
<property name="repeatInterval" value="300000"/>
</bean>
<!-- 每隔5秒钟执行一次 -->
<!-- <bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="firstComplexJobDetail"/>
<property name="cronExpression" value="0/5 * * ? * *"/>
</bean>-->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory">
<bean class="net.nengmao.backend.vendor.common.utils.quartz.MyJobFactory"/>
</property>
<property name="jobDetails">
<list>
<ref bean="simpleJobDetail"/>
<!-- <ref bean="firstComplexJobDetail"/>-->
</list>
</property>
<property name="triggers">
<list>
<ref bean="mySimpleTrigger"/>
<!--<ref bean="myCronTrigger"/>-->
</list>
</property>
</bean>
</beans>
第一种的任务类
/**
* 2018-5-18
* Quartz工具类(能传参)
*/
@Component
public class FirstScheduledJob extends QuartzJobBean{
private AnotherBean anotherBean;
public void setAnotherBean(AnotherBean anotherBean){
this.anotherBean = anotherBean;
}
@Override
protected synchronized void executeInternal(JobExecutionContext arg0)
throws JobExecutionException {
System.out.println("暂无需要修改的图片");
}
}
辅助传参的类
/**
* 2018-5-18
* Quartz工具类
*/
@Component("anotherBean")
public class AnotherBean {
public void printAnotherMessage() {
System.out.println("AnotherMessage");
}
}
注意:第一种存在Spring quartz定时任务service注入问题,具体原因可以百度,有很多解释,我这里直接给出方案
写一个辅助类,然后在Quartz配置文件中引入这个配置类,就是上面配置文件的红色部分
/**
* 2018-5-18
* by_will
* Quartz解决Spring注入失败辅助类
*/
public class MyJobFactory extends AdaptableJobFactory{
//这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入,这属于Spring的技术,不清楚的可以查看Spring的API.
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
然后还得把他引入到Spring中去,这样就可以解决Spring quartz定时任务service注入问题了
<bean id="jobFactory" class="net.nengmao.backend.vendor.common.utils.quartz.MyJobFactory"></bean>
第二种的任务类
/**
* 2018-5-18
* Quartz不能传参的
*/
@Component("myBean")
public class MyBean {
protected static Logger logger = LoggerFactory.getLogger(MyBean.class);
@Autowired
private ProductImgService productImgService;
@Autowired
private ProductImgDao productImgDao;
//int i=0;
public void printMessage() {
System.out.println("定时器开始检测是否有符合要求的图片");
}
}
编程式可以看看这个博客,挺好的:https://www.cnblogs.com/dupang/p/6063734.html
个人觉得学一个东西,最基本的就是要会用,用熟悉了自然会去研究实现原理,以上有问题欢迎各位大牛斧正,感谢