一、spring task
1. XML配置方式
(1)配置定时器 :<task:scheduler id="scheduler" pool-size="5" />
(2)配置定时任务:
<task:scheduled-tasks scheduler="scheduler" >
<task:scheduled ref="profitScheduler" method="execute" cron="0 0/2 * * * ?" initial-delay="5000" fixed-delay="3600000" />
</task:scheduled-tasks>
2. 注解方式
(1)方法上写注解: @Scheduled(cron = "0 0 3 * * ?")
(2)配置文件开启task:<task:annotation-driven/> (也可以配置定时器)
二、Quartz
1. 基本概念
(1)quartz是一个功能丰富的开源的任务调用系统,它可以创建简单或者复杂的几十、几百、甚至成千上万的job。此外,quartz调度器还支持JTA事务和集群
(2)Quartz是一个完全由java编写的开源作业调度框架,由OpenSymphony组织开源出来。所谓作业调度其实就是按照程序的设定,某一时刻或者时间间隔去执行某个代码
2. 重要组件
1) Scheduler —— 调度器
a. Scheduler被用来对Trigger和Job进行管理。Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中都拥有自己的唯一的组和名称用来进行彼此的区分,Scheduler可以通过组名或者名称来对Trigger和JobDetail来进行管理
b. 一个Trigger只能对应一个Job,但是一个Job可以对应多个Trigger。每个Scheduler都包含一个SchedulerContext,用来保存Scheduler的上下文。Job和Trigger都可以获取SchedulerContext中的信息
c. Scheduler包含两个重要的组件,JobStore和ThreadPool。JobStore用来存储运行时信息,包括Trigger,Schduler,JobDetail,业务锁等。ThreadPool就是线程池,Quartz有自己的线程池实现。所有任务的都会由线程池执行
2) Trigger —— 触发器
a. Trigger是用来定义Job的执行规则,主要有四种触发器,其中SimpleTrigger和CronTrigger触发器用的最多
I. SimpleTrigger:从某一个时间开始,以一定的时间间隔来执行任务。它主要有两个属性,repeatInterval 重复的时间间隔;repeatCount 重复的次数,实际上执行的次数是n+1,因为在startTime的时候会执行一次
II. CronTrigger:适合于复杂的任务,使用cron表达式来定义执行规则
3) job —— 任务
a. Job是一个任务接口,开发者定义自己的任务须实现该接口实现void execute(JobExecutionContext context)方法,JobExecutionContext中提供了调度上下文的各种信息
b. Job中的任务有可能并发执行,例如任务的执行时间过长,而每次触发的时间间隔太短,则会导致任务会被并发执行。如果是并发执行,就需要一个数据库锁去避免一个数据被多次处理。可以在execute()方法上添加注解@DisallowConcurrentExecution解决这个问题
4) jobDetail —— 任务详情
a. Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job
b. 因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。所以说JobDetail是任务的定义,而Job是任务的执行逻辑
3. 使用步骤
(1)引入jar包: quartz
(2)配置文件中注册job: <bean name="job1" class="com.quartz.demo.Job1Demo"/>
(3)注册jobDetail(要引入job以及其方法):
<bean id="jobDetail_1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 执行的类 -->
<property name="targetObject">
<ref bean="job1" />
</property>
<!-- 类中的方法 -->
<property name="targetMethod">
<value>sayHello</value>
</property>
</bean>
(4)注册触发器(要引入jobDetail以及写好corn表达式):
<bean id="cronTrigger_1" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="jobDetail_1" />
</property>
<!-- 每一秒钟执行一次 -->
<property name="cronExpression">
<value>0/1 * * * * ?</value>
</property>
</bean>
(5)注册调度器(只要把触发器引入就好了,jobDetail已经在触发器里了)
<!-- 总配置 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 添加触发器 -->
<property name="triggers">
<list>
<ref bean="cronTrigger_1" />
<ref bean="cronTrigger_2" />
</list>
</property>
</bean>
4. corn表达式
(1)按顺序依次为
a. 秒(0~59)
b. 分钟(0~59)
c. 小时(0~23)
d. 天(月)(0~31,但是你需要考虑你月的天数)
e. 月(0~11)
f. 天(星期)(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT)
g. 年份(1970-2099)
(2)其中每个元素可以是一个值(如6),一个连续区间(9-12),一个间隔时间(8-18/4)(/表示每隔4小时),一个列表(1,3,5),通配符
a. 0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
b. 0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
(3)由于"月份中的日期"和"星期中的日期"这两个元素互斥的,必须要对其中一个设置?
(4)“/”字符用来指定数值的增量
a. 在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟
b. 在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样
(5)“L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写
a. 在天(月)子表达式中,“L”表示一个月的最后一天
b. 在天(星期)自表达式中,“L”表示一个星期的最后一天,也就是SAT
c. “6L”表示这个月的倒数第6天,“FRIL”表示这个月的最一个星期五
d. 在使用“L”参数时,不要指定列表或范围,因为这会导致问题
5. 在项目中用到的实例
1. 直接建了一个web项目,ms_quartz
2. 把定时任务写成了一个json文件,里面有job_name、job_desc(url)、trigger_name、trigger_cron、remark等信息
3. 写了一个监听器,初始化的时候读这个json文件
4. 写个job实现类EshopJob实现Job,且实现execute()方法(里面的逻辑就是读取job_desc,开线程池调其他服务的get请求)
5. 遍历json数组,每次都addJob(String jobName, String jobDesc, String triggerName, Class jobClass, String cron) (传入4的类的.class)
6. 把传进来的配置信息转换为JobDetail(JobBuilder.newJob(jobClass).withIdentity(jobName, JOB_GROUP_NAME).withDescription(jobDesc).build())
7. 然后新建触发器,设定触发器 triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron))
8. 调度容器设置JobDetail和Trigger (sched.scheduleJob(jobDetail, trigger))
参考网址
注:文章是经过参考其他的文章然后自己整理出来的,有可能是小部分参考,也有可能是大部分参考,但绝对不是直接转载,觉得侵权了我会删,我只是把这个用于自己的笔记,顺便整理下知识的同时,能帮到一部分人。
ps : 有错误的还望各位大佬指正,小弟不胜感激