概述
最近项目中遇到任务调度的问题,学习总结如下:
Quartz是一个任务调度框架,由Java语言开发,可以用来做一些定时发送,监听事件等工作。
Quartz完成调度需要3步:
JobDetail:告诉调度器要做什么。
Trigger:告诉调度器什么时候做。
Scheduler:准备妥了就从这里start
依赖包:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
完整实例如下(xml和java):
spring.xml中
<!-- 完整配置:1.配置调度器工厂,2.配置要用的bean,3.配置调度器,4.配置触发器,5.把触发器加入调度器工厂里(SchedulerFactoryBean) -->
<!--配置调度器工厂-->
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!--配置触发器 -->
<property name="triggers">
<list>
<ref bean="sysTaskTimerTrigger"/><!--对应于触发器-->
</list>
</property>
</bean>
<!-- start -->
<!-- 要调用的bean -->
<bean id="SysTaskTimer" class="com.topcheer.framework.core.job.SysTaskTimer" /><!--对应于java类-->
<!-- 调度器 -->
<bean id="sysTaskTimerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="SysTaskTimer"></property>
<property name="targetMethod" value="timerRun"></property>
<!-- concurrent : false表示等上一个任务执行完后再开启新的任务 -->
<property name="concurrent" value="false"></property>
</bean>
<!-- 触发器 -->
<bean id="sysTaskTimerTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<!--调度器-->
<property name="jobDetail" ref="sysTaskTimerJobDetail"/><!--对应于调度器-->
<!-- 延迟3s执行 -->
<property name="startDelay" value="3000"/>
<!--每隔10s执行一次 -->
<property name="repeatInterval" value="10000"/>
</bean>
<!-- end -->
java代码如下:(部分代码省略)
@Component
public class SysTaskTimer {
//每次调用的这个方法
public void timerRun(){
try {
while(true){
if(myWorkQueue == null || myWorkQueue.size() == 0){
Map<Object,Object> param1 = new HashMap<Object,Object>();
param1.put("recordNum", 10);
List<FndSysTaskTimer> sysTaskTimerList = sysTaskTimerService.getSysTaskTimerHowMany(param1);
if(sysTaskTimerList == null || sysTaskTimerList.size() == 0){
if(myWorkQueue != null && threadPool != null){
threadPool.shutdownNow();
}
break;
}
if(sysTaskTimerList != null && sysTaskTimerList.size() > 0){
myWorkQueue=new ArrayBlockingQueue<Runnable>(10);
threadPool = new ThreadPoolExecutor(1,10,10L,TimeUnit.SECONDS,myWorkQueue);
for(int i=0 ; i < sysTaskTimerList.size(); i++){
setSysTaskTimer(sysTaskTimerList.get(i));
TaskThread taskThread = new TaskThread();
taskThread.init();
myWorkQueue.put(taskThread);
}
for(Runnable runnable : myWorkQueue){
threadPool.execute(runnable);
}
}
}
else{
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
下面针对以上的部门进行讲解:
一、配置调度工厂,是为了解决spring 注入问题,有两种方法:
1.
ApplicationContext content =
new ClassPathXmlApplicationContext("classpath:META-INF/applicationContext.xml");
userDaoI = content.getBean(UserDaoI.class);
使用ApplicationContex对象加载applicationContext.xml文件注入UserDaoI接口,但是这个方法不好的一点是每当用一个接口就要写一个,比较麻烦。
2.
<bean id="jobFactory" class="com.config.quartz.JobFactory"></bean>
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory" ref="jobFactory"></property>
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
</list>
</property>
</bean>
@Service("jobFactory")
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
先写一个类继承AdaptableJobFactory 抽象方法,不需要任何改动。
其实不用用继承,只需要写这个配置,映射jar里的类即可,如下:
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory" ref="jobFactory"></property>
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
</list>
</property>
</bean>
二、以上start--end部分,分别有两种方式:
定时任务详情(上面说的调度器)的两种方法:
1.第一种写法:
<!-- 要调用的bean -->
<bean id="SysTaskTimer" class="com.topcheer.framework.core.job.SysTaskTimer" /><!--对应于java类-->
<!-- 调度器 -->
<bean id="sysTaskTimerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="SysTaskTimer"></property>
<!-- 指定要调用的方法 timerRun -->
<property name="targetMethod" value="timerRun"></property>
<!-- concurrent : false表示等上一个任务执行完后再开启新的任务 -->
<property name="concurrent" value="false"></property>
</bean>
这种方式可以直接指定要调用的方法。
2.第二种写法:
<bean id="cronJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!--配置简单作业的目标类 -->
<property name="jobClass" value="com.topcheer.framework.core.job.MyCronJob"/>
<!--配置耐久性,如果一个任务不是durable,那么当没有Trigger关联它的时候,它就会被自动删除 -->
<property name="durability" value="true"/>
</bean>
public class MyCronJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
System.out.println("Quartz的cron表达式任务执行了:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
}
这种方式要继承QuartzJobBean类,实现executeInternal方法。两种方式任选一种。
触发器的两种写法:
1.第一种写法:
<bean id="sysTaskTimerTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="sysTaskTimerJobDetail"/>
<!-- 延迟3s执行 -->
<property name="startDelay" value="3000"/>
<!--每隔1000s执行一次 -->
<property name="repeatInterval" value="1000000"/>
</bean>
2.第二种写法:
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!--使用定时作业详情 或 使用简单作业详情- -->
<property name="jobDetail" ref="cronJobDetail"/>
<!--每隔5s执行一次 -->
<property name="cronExpression" value="*/5 * * * * ?"/>
<property name="startDelay" value="3000"></property>
</bean>
使用CronTriggerFactoryBean类配置,这个方法的好处在于可以使用cronExpression表达式。
cronExpression表达式介绍:
cron的表达式被用来配置CronTrigger实例。 cron的表达式是字符串,实际上是由七子表达式,描述个别细节的时间表。这些子表达式是分开的空白,代表:
1. Seconds
2. Minutes
3. Hours
4. Day-of-Month
5. Month
6. Day-of-Week
7. Year (可选字段)
例 "0 0 12 ? * WED" 在每星期三下午12:00 执行,
个别子表达式可以包含范围, 例如,在前面的例子里("WED")可以替换成 "MON-FRI", "MON, WED, FRI"甚至"MON-WED,SAT".
“*” 代表整个时间段.
每一个字段都有一套可以指定有效值,如
Seconds (秒) :可以用数字0-59 表示,
Minutes(分) :可以用数字0-59 表示,
Hours(时) :可以用数字0-23表示,
Day-of-Month(天) :可以用数字1-31 中的任一一个值,但要注意一些特别的月份
Month(月) :可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
Day-of-Week(每周):可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示
“/”:为特别单位,表示为“每”如“0/15”表示每隔15分钟执行一次,“0”表示为从“0”分开始, “3/20”表示表示每隔20分钟执行一次,“3”表示从第3分钟开始执行
“?”:表示每月的某一天,或第周的某一天
“L”:用于每月,或每周,表示为每月的最后一天,或每个月的最后星期几如“6L”表示“每月的最后一个星期五”
“W”:表示为最近工作日,如“15W”放在每月(day-of-month)字段上表示为“到本月15日最近的工作日”
““#”:是用来指定“的”每月第n个工作日,例 在每周(day-of-week)这个字段中内容为"6#3" or "FRI#3" 则表示“每月第三个星期五”
1)Cron表达式的格式:秒 分 时 日 月 周 年(可选)。
字段名 允许的值 允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日 1-31 , - * ? / L W C
月 1-12 or JAN-DEC , - * /
周几 1-7 or SUN-SAT , - * ? / L C #
年 (可选字段) empty, 1970-2099 , - * /
“?”字符:表示不确定的值
“,”字符:指定数个值
“-”字符:指定一个值的范围
“/”字符:指定一个值的增加幅度。n/m表示从n开始,每次增加m
“L”字符:用在日表示一个月中的最后一天,用在周表示该月最后一个星期X
“W”字符:指定离给定日期最近的工作日(周一到周五)
“#”字符:表示该月第几个周X。6#3表示该月第3个周五
2)Cron表达式范例:
每隔5秒执行一次:*/5 * * * * ?
每隔1分钟执行一次:0 */1 * * * ?
每天23点执行一次:0 0 23 * * ?
每天凌晨1点执行一次:0 0 1 * * ?
每月1号凌晨1点执行一次:0 0 1 1 * ?
每月最后一天23点执行一次:0 0 23 L * ?
每周星期天凌晨1点实行一次:0 0 1 ? * L
在26分、29分、33分执行一次:0 26,29,33 * * * ?
每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?
每天上午10:15触发 :0 15 10 * * ? *
2005年的每天上午10:15触发:0 15 10 * * ? 2005
Quartz属于重量级的定时任务框架,我们一般都会选择轻量级的如Spring Task定时任务进行开发。
参考:
https://segmentfault.com/a/1190000012926491
https://blog.csdn.net/x6582026/article/details/52947878
https://www.cnblogs.com/hafiz/p/6159280.html
最后
以上就是优美电脑为你收集整理的spring任务调度的全部内容,希望文章能够帮你解决spring任务调度所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复