转自:https://blog.csdn.net/JY_He/article/details/52198952
quarz中定时任务包括三个部分:
Schedule(任务调度器),Job(作业任务)和Trigger(触发器)
Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。
JobDetail:Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。
Trigger:是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。
当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案。
Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。
一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。
使用案列:
public class HelloWord implements Job{
//实现自己的定时方法
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.println("hello world " + new Date());
}
}
public class SimpleExample {
public static void main(String[] args) throws SchedulerException{
SimpleExample example=new SimpleExample();
example.run();
}
public void run() throws SchedulerException {
//获取scheduler实例
Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
//当前时间
Date runTime=new Date();
//定义一个 job 对象并绑定我们写的 HelloWord 类
// 真正执行的任务并不是Job接口的实例,而是用反射的方式实例化的一个JobDetail实例
JobDetail job=JobBuilder.newJob(HelloWord.class).withIdentity("job1","group1").build();
// 定义一个触发器,startAt方法定义了任务应当开始的时间 .即下一个整数分钟执行
Trigger trigger=TriggerBuilder.newTrigger().withIdentity("trigger1","group1").startAt(runTime).build();
/* .withIdentity("myTrigger","group1")
.startNow()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever())
.build();
*/
// 将job和Trigger放入scheduler
scheduler.scheduleJob(job, trigger);
//启动
scheduler.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
scheduler.shutdown();
}
}
quarz整合Spring框架案例
第一种方式
需要继承JobBean,并重写executeInternal(JobExecutionContext context),然后配置spring-quratz.xml文件,里配置三部分:1.任务调用类;2.任务调用方式;3.任务调用工厂。
public class QuartzTask extends QuartzJobBean{
private int timeout;
private static int i = 0;
//调度工厂实例化后,经过timeout时间开始执行调度
public void setTimeout(int timeout) {
this.timeout = timeout;
}
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
System.out.println("task running..."+ ++i + "进行中...");
}
}
XML 配置
<!-- 配置任务类 -->
<bean id="quartzTask" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="name" value="exampleJob"></property>
<property name="quartzClass" value="spring.demo.pojo.QuartzTask"></property>
<property name="jobDataAsMap">
<map>
<entry key="timeout" value="0" />
</map>
</property>
</bean>
<!-- 配置触发器 -->
<bean id="cronTriggerBean"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="quartzTask" />
</property>
<!-- cron表达式 -->
<property name="cronExpression">
<value>10,15,20,25,30,35,40,45,50,55 * * * * ?</value>
</property>
</bean>
<!-- 调度工厂 -->
<bean id="SpringJobSchedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTriggerBean" />
</list>
</property>
</bean>
第二种方式:
不需要继承基类,这样仍然是pojo,而是在spring-quratz.xml配置文件中,配置包装类,其他两个配置与上述一样。
public class QuartzJob {
public void work(){
System.out.println("work running...");
}
}
XML配置:
<!-- 配置任务类 -->
<bean id="quartzJob" class="spring.demo.pojo.QuartzJob"></bean>
<bean id="jobTask"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 需要包装的类,即调度类 -->
<property name="targetObject">
<ref bean="quartzJob" />
</property>
<!-- 调用类中的方法 -->
<property name="targetMethod">
<!-- 具体的方法 -->
<value>work</value>
</property>
</bean>
<!-- 配置触发器 -->
<bean id="cronTriggerBean"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="jobtask" />
</property>
<!-- cron表达式 -->
<property name="cronExpression">
<value>10,15,20,25,30,35,40,45,50,55 * * * * ?</value>
</property>
</bean>
<!-- 调度工厂 -->
<bean id="SpringJobSchedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTriggerBean" />
</list>
</property>
</bean>
.第三种方式
通过@Scheduled注解的方式实现,需要修改applicationContext.xml三个部分内容:
1.xmlns添加:
xmlns:task=“http://www.springframework.org/schema/task”
2.xsi:schemaLocation添加
http://www.springframework.org/schema/task/spring-task-3.1.xsd
3.applicationContext.xml中添加
task:annotation-driven/
注解方法开发
@Service
public class QuartzService {
@Scheduled(cron = "0/2 * * * * *")
public void process() {
System.out.println("job run...");
}
public static void main(String[] args) throws InterruptedException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
while (true) {
System.out.println("main running...");
Thread.sleep(10000);
}
}
}
JobExecutionContext与JobDataMap
JobExecutionContext可以理解为Job实例的上下文,可以通过它获取job运行时的环境以及属性信息,一个Job对应一个JobExecutionContext的实例。当Scheduler调用一个Job时就会将JobExecutionContext传递给job的execute方法。
JobDataMap实现了Map接口,用法同Map类似,它可以装在任何可序列化的数据对象,执行Job时用来传递数据,JobDataMap存在JobExecutionContext中,要通过JobExecutionContext来获取。
Test代码:
public class TestHelloJob2
{
public static void main( String[] args ) throws SchedulerException
{
/*创建JobDetail实例,并与HelloJob绑定;Job的名字是myjob,隶属于job_group组*/
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myjob", "job_group")
.usingJobData("data1", "Data1 Information")
.usingJobData("data2", 10000D)
.build();
/*创建Trriger实例,指定Job每隔3秒钟执行一次*/
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("mytrigger", "trigger_group")
.usingJobData("data2", 20000D)
.usingJobData("data3", "Data3 Information")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever())
.build();
/*创建SchedulerFactory实例,把jobDetail与trigger绑定在一起*/
SchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
}
}
创建作业,实现Job接口,在job中获取传输的数据
public class HelloJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sf.format(new Date()));
/*获取job的属性*/
JobKey key = context.getJobDetail().getKey();
System.out.println("Job name : " + key.getName() + "; Job group : " + key.getGroup());
/*获取Trigger的属性*/
TriggerKey tKey = context.getTrigger().getKey();
System.out.println("Trigger name : " + tKey.getName() + ": Trigger group : " + tKey.getGroup());
/*获取JobDetail中的DataMap中属性*/
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobData1 = dataMap.getString("data1");
Double jobData2 = dataMap.getDouble("data2");
System.out.println("jobData1 : " + jobData1 + " ; jobData2 : " + jobData2);
/*获取Trigger中的DataMap属性*/
JobDataMap tDataMap = context.getTrigger().getJobDataMap();
Double triggerData2 = tDataMap.getDouble("data2");
String triggerData3 = tDataMap.getString("data3");
System.out.println("triggerData2 : " + triggerData2 + "; triggerData3 : " + triggerData3);
System.out.println("This is hello job……");
System.out.println("------------------------------------------");
}
}