本教程的重点是防止Quartz任务并行和在任务中获取Spring中Bean的方法,对应教程第三和第四部分。
Spring:
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#scheduling-quartz
Quartz:
http://www.quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/
Quartz的文档看前几章,知道Job,JobDetail,Trigger和Scheduler分别是做什么用的即可。Spring中关于Quartz的相关文档需要仔细阅读,其中的相关配置看懂后直接粘贴复制到项目配置文件中,更改为自己需要的配置即可。
<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="example.ExampleJob"/>
<property name="jobDataAsMap">
<map>
<entry key="timeout" value="5"/>
map>
property>
bean>
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="exampleBusinessObject"/>
<property name="targetMethod" value="doIt"/>
<property name="concurrent" value="false"/>
bean>
首先说"JobDetail配置 2",官方介绍如下:Often you just need to invoke a method on a specific object. Using the MethodInvokingJobDetailFactoryBean you can do exactly this。按照官方的意思,就是说简单情况下,如果你的定时任务只是需要调用某个Spring对象的某个方法,可以用这个配置来简单配置下,concurrent设置为false可以防止任务并发执行。这种配置在简单的情况下可用,但是功能不强,用处不大。
重点介绍"JobDetail配置 1":
package example;
public class ExampleJob extends QuartzJobBean {
private int timeout;
/**
* Setter called after the ExampleJob is instantiated
* with the value from the JobDetailFactoryBean (5)
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
}
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
// do the actual work
}
}
在executeInternal中进行实际业务逻辑。
<entry key="timeout" value="5"/>
只要是继承的QuartzJobBean,就可以通过这种方式直接向Job的属性中传递值,如上例中的
private int timeout;
/**
* Setter called after the ExampleJob is instantiated
* with the value from the JobDetailFactoryBean (5)
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
}
然后在executeInternal方法中就可以直接使用timeout的值了,如下:
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
System.out.println(timeout);
}
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"/>
<property name="startDelay" value="10000"/>
<property name="repeatInterval" value="50000"/>
bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="exampleJob"/>
<property name="cronExpression" value="0 0 6 * * ?"/>
bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
<ref bean="simpleTrigger"/>
list>
property>
bean>
上面配置可直接粘贴复制拿来用,list里配置所有需要使用的trigger。
按照Spring的官方文档,只介绍说MethodInvokingJobDetailFactoryBean(请参看教程前面相关部分)有一个concurrent属性可以用来控制任务是否可以并行。请注意,这个"concurrent"属性是MethodInvokingJobDetailFactoryBean独有的,JobDetailFactoryBean是没有这个属性的,所以是无法给JobDetailFactoryBean配置concurrent属性的。网上很多教程说给"JobDetailFactoryBean"配置"concurrent"来防止Quartz任务并行是错误的。由于MethodInvokingJobDetailFactoryBean功能太弱,实际开发中用不多,所以防止JobDetailFactoryBean任务并行是最重要,配置很简单,如下:
package example;
//只需要在Job类上加上这个注解即可
@DisallowConcurrentExecution
public class ExampleJob extends QuartzJobBean {
private int timeout;
/**
* Setter called after the ExampleJob is instantiated
* with the value from the JobDetailFactoryBean (5)
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
}
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
// do the actual work
}
}
如上示例,只需要在Job类上加上@DisallowConcurrentExecution
注解即可。这才是正确的方法。
详情请见:https://blog.csdn.net/lianjunzongsiling/article/details/53690956
原理很简单,通过ContextLoader
工具的getCurrentWebApplicationContext()
方法获取WebApplicationContext
,然后通过WebApplicationContext
的相关方法获取Bean(通常我们需要获取的类也就是各种Service了,这种情况下用这种办法是最简单的)。