Quartz使用总结

编程

声明:这里参考了许多博客,加上自身的使用总结。如果您是知识的原创者,可以在评论区写上您的博文链接~

一、删除任务的顺序

delete from qrtz_cron_triggers; #存放cron类型的触发器

delete from qrtz_simple_triggers; #简单触发器的信息

delete from qrtz_triggers; #触发器的基本信息

delete from qrtz_job_details; #存放任务的详细信息

delete from qrtz_scheduler_state; #调度器状态

delete from qrtz_locks; #存储程序的悲观锁的信息

二、注入Service失败原因分析

1. 这个Job是由quartz实例化出来的,不受Spring的管理,所以就导致注入失败。

2. 在quartz框架中,Job 是通过反射出来的实例,不受spring的管理。

Scheduler现在交给Spring生成,在Spirng-context-support的jar包下

org.springframework.scheduling.quartz包中有个SpringBeanJobFactory的类,

job实例通过该类的createJobInstance方法创建。根据Scheduler context、job data map and trigger data map填充其属性。

但是创建的job实例并没被spring管理,这就需要我们自定义一个类将创建的job添加到applicationContext中,

该类需要继承SpringBeanJobFactory,并实现ApplicationContextAware接口。

3. ApplicationContextAware接口的作用:Spring容器会检测容器中的所有Bean,

如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,

自动调用该Bean的setApplicationContextAware()方法,调用该方法时,

会将容器本身作为参数传给该方法——该方法中的实现部分将Spring传入的参数(容器本身)赋给

该类对象的applicationContext实例变量,因此接下来可以通过该applicationContext实例变量来访问容器本身。

三、解决自动注入的问题

  1. 新增一个类

public class CustomJobFactory extends SpringBeanJobFactory{

@Autowired

private AutowireCapableBeanFactory capableBeanFactory;

@Override

protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {

//调用父类的方法

Object jobInstance = super.createJobInstance(bundle);

//进行注入

capableBeanFactory.autowireBean(jobInstance);

return jobInstance;

}

}

  1. 修改spring的配置文件

<!-- 定时任务配置 start -->

<bean id="customJobFactory" class="com.gxuwz.quartz.CustomJobFactory"></bean>

<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">

<property name="dataSource" ref="dataSource"></property>

<!--可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 -->

<property name="overwriteExistingJobs" value="true" />

<!--必须的,QuartzScheduler 延时启动,应用启动完后 QuartzScheduler 再启动 -->

<property name="startupDelay" value="10" />

<!-- 设置自动启动 -->

<property name="autoStartup" value="true" />

<property name="jobFactory" ref="customJobFactory"></property>

<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />

<property name="configLocation" value="classpath:spring-quartz.properties" />

</bean>

<!-- 定时任务配置 end -->

四、常用的两个注解

@DisallowConcurrentExecution

禁止并发执行多个相同定义的JobDetail, 这个注解是加在Job类上的, 但意思并不是不能同时执行多个Job,

而是不能并发执行同一个Job Definition(由JobDetail定义), 但是可以同时执行多个不同的JobDetail。

即对于同一个Job任务不允许并发执行,但对于不同的job任务不受影响。

@PersistJobDataAfterExecution

保存在JobDataMap传递的参数。加在Job上,表示当正常执行完Job后, JobDataMap中的数据应该被改动, 以被下一次调用时用。

五、提供一个模板

@Component

@DisallowConcurrentExecution

public class MyTimer implements Job {

private Scheduler scheduler;

@Autowired

private IHelloService helloService;

public MyTimer() { super(); }

@Autowired

public void setScheduler(Scheduler scheduler) {

this.scheduler = scheduler;

start();

}

public Scheduler getScheduler() {

return scheduler;

}

@Override

public void execute(JobExecutionContext arg0) throws JobExecutionException {

helloService.say();

}

public void start() {

// 1.创建JobDetail

// 2.创建Trigger,如果使用了cron表达式,那么startNow()和startAt(date)方法会失效

// 3.执行任务

if(!scheduler.checkExists(jobDetail.getKey())){

scheduler.scheduleJob(jobDetail, trigger);

}

}

}

六、执行定时任务时,报了一个错误

"Could not obtain transaction-synchronized Session for current thread"

分析

1. quartz是启动子线程去执行的

2. SessionFactory的getCurrentSession并不能保证在没有当前Session的情况下会自动创建一个新的,

这取决于CurrentSessionContext的实现,SessionFactory将调用CurrentSessionContext的currentSession()方法来获得Session。

在Spring中,如果我们在没有配置事务并且没有事先调用SessionFactory.openSession()的情况直接调用getCurrentSession(),

那么程序将抛出"No Session found for current thread"异常。如果配置了事务并且通过@Transactional或者声明的方式

配置的事务边界,那么Spring会在开始事务之前通过AOP的方式为当前线程创建Session,此时调用getCurrentSession()将得到正确结果。

解决方案

使用声明式事务或者注解式事务,方法需要在事务内执行

以上是 Quartz使用总结 的全部内容, 来源链接: utcz.com/z/511471.html

回到顶部