很多的项目文件都需要备份,Linux系统提供了一个crontab可以帮助我们完成这个定时任务
http://www.cnblogs.com/zhenyuyaodidiao/p/4755649.html
一、概述
- cron 是类 Unix 系统中最为实用的工具之一;
- 定时任务(cron job)被用于执行需要周期性执行的命令,利用这个定时任务,可以配置命令或者脚本,让它们在某个设定的时间内周期性地运行;
- cron 服务在系统后台运行,即以守护进程的方式运行,并且会持续地检查
/etc/crontab
文件和目录/etc/cron.*/
以及/var/spool/cron/
;
二、Linux系统中的Cron的一些常见命令
-
查看目前的定时任务
crontab -l
-
制定定时任务
- 生成cron表达式:http://cron.qqe2.com/
- 注意cron只能精确到分钟,有分钟,小时,日,周,月;而且生成的表达式中的?修改成*,否则报错
- 生成文件
crontab -e
- 每分钟执行一次的内容,保存后就会生效
***** sh <sh-file>
- 查看执行日志
tail -f /var/log/cron
- 生成cron表达式:http://cron.qqe2.com/
五、Corn表达式的编写
-
Corn表达式组成:
<seconds> <minutes> <hours> <day-of-month> <month> <day-of-week> [<year>]
域 取值范围 允许的特殊字符 <seconds>域 秒,有效范围为0-59的整数 ,
-
*
/
<minutes>域 分,有效范围为0-59的整数 ,
-
*
/
<hours>域 时,有效范围为0-23的整数 ,
-
*
/
<day-of-month>域 月中日,有效范围为0-31的整数 ,
-
*
/
?
L
W
C
<month>域 月,有效范围为1-12的整数或JAN-DEC ,
-
*
/
<day-of-week>域 周中天,有效范围为1-7的整数或SUN-SAT ,
-
*
/
?
L
C
#
<year>域 年,可选填项,有效范围为1970-2099年 ,
-
*
/
-
通配符
- 各个通配符的含义:
通配符 含义 示例 , 表示列出当前域离散值 如: 0 0 10 12,15 * *
表示每月的12号和15号的10点0分0秒触发- 表示当前域的范围 如: 0 0 10 12-15 * *
表示每月的12号到15号的10点0分0秒触发* 表示匹配该域的任意值 在<minutes>域使用 *,即表示每分钟都会触发事件 / 用来表达一个周期性的表达方式 如:0 10/8 * * * *:每个小时的10分开始,每8分钟触发一次 ? 表示不确定,只能用在<day-of-month>和<day-of-week>两个域,一般用于两个有关联的域之一上,一个确定了,另外一个不能确定,就只能填写? 如:想在每月的20日触发,不管20日星期几,则只能使用如下写法: 0 0 12 20 * ?, 其中最后一位周天只能用 ?,而不能使用 *,如果使用 * 表示不管星期几都会触发,实际上并不是这样。 L 表示最后一个当前域的值,只能用在<day-of-month>和<day-of-week>两个域 如: 0 0 10 * * 5L
表示每月的最后一个周四的10点0分0秒触发W 表示有效工作日(周一到周五),只能出现在<day-of-month>域,,系统将在离指定日期的最近的有效工作日触发事件,而且W的寻找不会跨过月份 如: 0 0 10 8W * ?
表示:如果这个月8号是周一到周五的某天,那么在周五的10点0分0秒触发事件,如果当月8号是周六会在前一天周五即7号的10点触发, 如果是当天是周日,那么就会在最近的工作日即下周一即8号的10点触发;但是如果这里的8是1号,而且这个1号是周六,那么触发的时间只能是下周一即3号的10点触发,如果这个是周日,那就是2号的10点触发LW 表示一个月的最后一个工作日 如 C 。。。 。。。 # 。。。 。。。
- 各个通配符的含义:
四、Java中使用Cron ~ Spring-Schedule
在日常开发的之中,在项目中你或许会遇到定时任务,是一定,那么你会怎么做?是使用Timer Task,还是使用大名鼎鼎的Quatz,还是会选择Spring-Schedule等,答案不重要,重要的是你心里要有根据的取舍和选择,好了,我来补充一个关于定时任务的,由于都是定时任务,所以就放在了Linux的计划任务这篇中,作为一个补充出现。
-
cron表达式
- 常用的cron表达式:
- 每天0点
0 0 0 * * ?
- 每天23点
0 0 23 * * ?
- 每6小时
0 0 */6 * * ?
- 每1小时
0 0 */6 * * ?
- 每1分钟
0 */1 * * * ?
- 例01:每隔5秒执行一次:
*/5 * * * * ?
- 例02:每隔5分执行一次:
0 */5 * * * ?
- 例03:在26分、29分、33分执行一次:
0 26,29,33 * * * ?
- 例04:每天半夜12点30分执行一次(注意日期域为0不是24):
0 30 0 * * ?
- 例05:每天凌晨1点执行一次:
0 0 1 * * ?
- 例06:每天上午10:15执行一次:
0 15 10 ? * * 或 0 15 10 * * ? 或 0 15 10 * * ? *
- 例07:每天中午十二点执行一次:
0 0 12 * * ?
- 例08:每天14点到14:59分,每1分钟执行一次:
0 * 14 * * ?
- 例09:每天14点到14:05分,每1分钟执行一次:
0 0-5 14 * * ?
- 例10:每天14点到14:55分,每5分钟执行一次:
0 0/5 14 * * ?
- 例11:每天14点到14:55分,和18点到18点55分,每5分钟执行一次:
0 0/5 14,18 * * ?
- 例12:每天18点执行一次:
0 0 18 * * ?
- 例13:每天18点、22点执行一次:
0 0 18,22 * * ?
- 例14:每天7点到23点,每整点执行一次:
0 0 7-23 * * ?
- 例15:每个整点执行一次:
0 0 0/1 * * ?
- 例16:每天凌晨2点
0 0 2 * * ?
- 例17:每天隔一小时
0 * */1 * * ?
- 例17:每天12点触发
0 12 * * ?
- 例18:每天10点15分触发
15 10 ? * * 15 10 * * ? 15 10 * * ? *
- 例19:2005年每天10点15分触发
15 10 * * ?
- 例20:每天下午的 2点到2点59分每分触发
* 14 * * ?
- 例21:每天下午的 2点到2点59分(整点开始,每隔5分触发)
0/5 14 * * ?
- 例22:每天下午的 2点到2点59分(整点开始,每隔5分触发)
0/5 14,18 * * ?
- 例23:每天下午的 2点到2点05分每分触发
0-5 14 * * ?
- 例24:3月分每周三下午的 2点10分和2点44分触发 (特殊情况,在一个时间设置里,执行两次或 两次以上的情况)
10,44 14 ? 3 WED
- 例25:每周5凌晨2点59分触发;
59 2 ? * FRI
- 例26:从周一到周五每天上午的10点15分触发
17 10 ? * MON-FRI
- 例27:每月15号上午10点15分触发
15 10 15 * ?
- 例28:每月最后一天的10点15分触发
15 10 L * ?
- 例29:每月最后一周的星期五的10点15分触发
15 10 ? * 6L
- 例30:从2002年到2005年每月最后一周的星期五的10点15分触发
15 10 ? * 6L 2002-2005
- 例31:每月的第三周的星期五开始触发
15 10 ? * 6#3
- 例32:每月的第一个中午开始每隔5天触发一次
0 12 1/5 * ?
- 例33:每年的11月11号 11点11分触发(光棍节)
11 11 11 11 ?
- 每天0点
- 常用的cron表达式:
-
配置Spring-Schedule
- 在Spring的配置文件中添加配置:
<task:annotation-driven/>
- 如果IDE没有添加schema,则需要手动添加:
xmlns:task="http://www.springframework.org/schema/task" http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"
- 如果IDE没有添加schema,则需要手动添加:
- 在Spring的配置文件中添加配置:
-
添加计划任务代码:
import org.shreker.core.service.IOrderService; import org.shreker.core.util.PropertiesUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Slf4j @Component public class UpdateOrderStatusTask { @Autowired private IOrderService iOrderService; @Scheduled(cron = "0 */1 * * * ?") public void updateOrderTask() { int hour = Integer.parseInt(PropertiesUtil.getProperty("order.close.time.hour", "1")); iOrderService.closeOrder(hour); } }
五、Cron和CronTab
六、单节点Quartz引入
- 引入 pom(如果你的项目是用 SpringBoot,查看一下已经包含了 quartz 的包)
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency>
- 编写监听器
import com.ainemo.dcs.statistics.apimonitor.task.QuartzScheduler; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.impl.StdSchedulerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextRefreshedEvent; /** * created by `ShrekerNil` at 2019/03/29 10:27 */ @Configuration public class ApplicationStartQuartzJobListener implements ApplicationListener<ContextRefreshedEvent> { Logger logger = LoggerFactory.getLogger(ApplicationStartQuartzJobListener.class); @Autowired private QuartzScheduler quartzScheduler; /** * 初始启动quartz */ @Override public void onApplicationEvent(ContextRefreshedEvent event) { try { logger.info("[<QUZRTZ DISPATCH>]Starting Quartz task ..."); quartzScheduler.startJob(); } catch (SchedulerException e) { logger.error("[<QUZRTZ DISPATCH>]ERROR: ", e); } } /** * 初始注入scheduler */ @Bean public Scheduler scheduler() throws SchedulerException { SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory(); return schedulerFactoryBean.getScheduler(); } }
- 编写任务
import java.util.Date; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; /** * created by `ShrekerNil` at 2019/03/29 10:27 */ public class Interval10Task implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("[<QUZRTZ DISPATCH>]开始:" + new Date()); // TODO 业务 System.out.println("[<QUZRTZ DISPATCH>]########################################- analysis-origin-log-info-10 -########################################"); System.out.println("[<QUZRTZ DISPATCH>]结束:" + new Date()); } }
- 编写调度器
import java.util.Date; import org.quartz.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * created by `yanqinglong` at 2019/03/29 10:20 */ @Component public class QuartzScheduler { @Autowired private Scheduler scheduler; /** * 开始执行所有任务 */ public void startJob() throws SchedulerException { startJob1(scheduler); startJob2(scheduler); // TODO 其他的任务 scheduler.start(); } /** * 获取Job信息 */ public String getJobInfo(String name, String group) throws SchedulerException { TriggerKey triggerKey = new TriggerKey(name, group); CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); return String.format("time:%s,state:%s", cronTrigger.getCronExpression(), scheduler.getTriggerState(triggerKey).name()); } /** * 修改某个任务的执行时间 */ public boolean modifyJob(String name, String group, String time) throws SchedulerException { Date date = null; TriggerKey triggerKey = new TriggerKey(name, group); CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); String oldTime = cronTrigger.getCronExpression(); if (!oldTime.equalsIgnoreCase(time)) { CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(time); CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group) .withSchedule(cronScheduleBuilder).build(); date = scheduler.rescheduleJob(triggerKey, trigger); } return date != null; } /** * 暂停所有任务 */ public void pauseAllJob() throws SchedulerException { scheduler.pauseAll(); } /** * 暂停某个任务 */ public void pauseJob(String name, String group) throws SchedulerException { JobKey jobKey = new JobKey(name, group); JobDetail jobDetail = scheduler.getJobDetail(jobKey); if (jobDetail == null) return; scheduler.pauseJob(jobKey); } /** * 恢复所有任务 */ public void resumeAllJob() throws SchedulerException { scheduler.resumeAll(); } /** * 恢复某个任务 */ public void resumeJob(String name, String group) throws SchedulerException { JobKey jobKey = new JobKey(name, group); JobDetail jobDetail = scheduler.getJobDetail(jobKey); if (jobDetail == null) return; scheduler.resumeJob(jobKey); } /** * 删除某个任务 */ public void deleteJob(String name, String group) throws SchedulerException { JobKey jobKey = new JobKey(name, group); JobDetail jobDetail = scheduler.getJobDetail(jobKey); if (jobDetail == null) return; scheduler.deleteJob(jobKey); } /** * 简单调取器 */ private void startJob1(Scheduler scheduler) throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(Interval10Task.class).withIdentity("analysis-origin-log-info-10", "Interval10Task").build(); SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(); //simpleScheduleBuilder.withIntervalInMinutes(10); simpleScheduleBuilder.withIntervalInSeconds(10); SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger().withIdentity("analysis-origin-log-info-10", "Interval10Task").withSchedule(simpleScheduleBuilder).build(); scheduler.scheduleJob(jobDetail, simpleTrigger); } /** * 基于 Crontab 的调度器 */ private void startJob2(Scheduler scheduler) throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(Interval30Task.class).withIdentity("job3", "group3").build(); CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0 10 * * * ?"); CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("job2", "group2").withSchedule(cronScheduleBuilder).build(); scheduler.scheduleJob(jobDetail, cronTrigger); } }
- 问题:在
Interval10Task
中无法注入 Service,解决方案:先获取 ApplicationContext,在通过 ApplicationContext 来获取其中的 Service 对象,这里记一下,先贴出另外一种方案:- 编写 Quartz 环境监视器
import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import org.quartz.SchedulerException; import org.quartz.ee.servlet.QuartzInitializerListener; import org.quartz.impl.StdSchedulerFactory; import org.springframework.stereotype.Component; /** * Quartz 环境监听器 * created by `ShrekerNil` at 2019/04/03 10:27 */ @Component public class QuartzServletContextListener extends QuartzInitializerListener { public static final String CONTEXT_NAME = "servletContext"; @Override public void contextDestroyed(ServletContextEvent sce) { super.contextDestroyed(sce); } @Override public void contextInitialized(ServletContextEvent sce) { super.contextInitialized(sce); ServletContext servletContext = sce.getServletContext(); StdSchedulerFactory factory = (StdSchedulerFactory) servletContext.getAttribute(QuartzInitializerListener.QUARTZ_FACTORY_KEY); try { factory.getScheduler().getContext().put(QuartzServletContextListener.CONTEXT_NAME, servletContext); } catch (SchedulerException e) { e.printStackTrace(); } } }
- 在 Job 的 execute 方法中添加如下代码
ServletContext servletContext = null; try { servletContext = (ServletContext) context.getScheduler().getContext().get(QuartzServletContextListener.CONTEXT_NAME); } catch (SchedulerException e1) { LOGGER.error("[<QUARTZ DISPATCH>] - ERROR :", e1); } if (servletContext == null) { LOGGER.error("[<QUARTZ DISPATCH>] - ERROR : Cannot load Servlet Context"); return; } WebApplicationContext cxt = (WebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); apiInvocationStatisService = (ApiInvocationStatisService) cxt.getBean("apiInvocationStatisService"); originLogInfoService = (OriginLogInfoService) cxt.getBean("originLogInfoService");
- 编写 Quartz 环境监视器