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实例变量来访问容器本身。
三、解决自动注入的问题
- 新增一个类
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;
}
}
- 修改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