需要:使用springboot,实现定时任务可配置。
定时任务可在代码中写死,在配置文件中配置,这些都不能实现定时任务在服务器不重启的情况下可配置。
为实现需求,使定时任务在时间表达式或者定时任务类更改时,实现定时任务的重新设置并启动。
- pom包配置
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.5.8.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>1.5.8.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>
<!-- jdbc driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
</dependencies>
项目采用springboot框架1.5.8版本,未采用quartz框架,使用spring-boot-devtools包springboot自带的定时任务完成。
因为spring2.0版本下尚未集成quartz,根据需求采用这种模式。
2.配置文件
#jpa spring.jpa.generate-ddl: false spring.jpa.show-sql: true spring.jpa.hibernate.ddl-auto: none spring.jpa.properties.hibernate.format_sql: false
#DataSource配置 spring.datasource.url=${pom.datasource.url} spring.datasource.username=${pom.datasource.username} spring.datasource.password=${pom.datasource.password} spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
3.application启动项
1 @ComponentScan(basePackages = { "com.deleba.quartz" }) 2 @SpringBootApplication 3 @EnableScheduling 4 public class QuartzApplication { 5 6 public static void main(String[] args) { 7 SpringApplication app = new SpringApplication(MCloudQuartzApplication.class); 8 app.addListeners(new StartApplicationListener()); 9 app.run(args); 10 } 11 12 @Bean("sessionFactory") 13 public HibernateJpaSessionFactoryBean sessionFactory() { 14 return new HibernateJpaSessionFactoryBean(); 15 } 16 17 @Bean 18 public ThreadPoolTaskScheduler threadPoolTaskScheduler() { 19 return new ThreadPoolTaskScheduler(); 20 } 21 }
4.定时任务实体
1 package com.deleba.quartz.entity; 2 3 import java.io.Serializable; 4 import java.util.Date; 5 6 import javax.persistence.Entity; 7 import javax.persistence.GeneratedValue; 8 import javax.persistence.GenerationType; 9 import javax.persistence.Id; 10 import javax.persistence.Table; 11 12 @Entity 13 @Table(name = "quartz_cron") 14 public class CronVO implements Serializable { 15 16 private static final long serialVersionUID = -3406421161273529348L; 17 @Id 18 @GeneratedValue(strategy = GenerationType.AUTO) 19 private Integer cronId; 20 /** 21 * cron 22 */ 23 private String cron; 24 /** 25 * 定时任务名称 26 */ 27 private String quartzName; 28 /** 29 * 状态("1":有效 "0":无效) 30 */ 31 private Integer status; 32 /** 33 * 定时任务类 34 */ 35 private String schedulerClass; 36 /** 37 * 时间戳 38 */ 39 private Date ts; 40 41 public CronVO() { 42 } 43 44 public Date getTs() { 45 return ts; 46 } 47 48 public void setTs(Date ts) { 49 this.ts = ts; 50 } 51 52 public String getSchedulerClass() { 53 return schedulerClass; 54 } 55 56 public void setSchedulerClass(String schedulerClass) { 57 this.schedulerClass = schedulerClass; 58 } 59 60 public String getQuartzName() { 61 return quartzName; 62 } 63 64 public void setQuartzName(String quartzName) { 65 this.quartzName = quartzName; 66 } 67 68 public Integer getCronId() { 69 return cronId; 70 } 71 72 public void setCronId(Integer cronId) { 73 this.cronId = cronId; 74 } 75 76 public String getCron() { 77 return cron; 78 } 79 80 public void setCron(String cron) { 81 this.cron = cron; 82 } 83 84 public Integer getStatus() { 85 return status; 86 } 87 88 public void setStatus(Integer status) { 89 this.status = status; 90 } 91 92 }
5.定时任务trigger
1 package com.deleba.quartz.trigger; 2 3 import java.util.Date; 4 5 import org.apache.commons.lang3.StringUtils; 6 import org.springframework.scheduling.Trigger; 7 import org.springframework.scheduling.TriggerContext; 8 import org.springframework.scheduling.support.CronTrigger; 9 10 /** 11 * 定时任务trigger 12 * 13 * @author Administrator 14 * 15 */ 16 public class QuartzTrigger implements Trigger { 17 18 private String cron; 19 20 public McloudTrigger(String cron) { 21 super(); 22 this.cron = cron; 23 } 24 25 @Override 26 public Date nextExecutionTime(TriggerContext triggerContext) { 27 if (StringUtils.isBlank(cron)) { 28 return null; 29 } 30 // 定时任务触发,可修改定时任务的执行周期 31 CronTrigger trigger = new CronTrigger(cron); 32 Date nextExecDate = trigger.nextExecutionTime(triggerContext); 33 return nextExecDate; 34 } 35 36 }
6.定时任务线程
1 package com.deleba.quartz.thread; 2 3 import org.slf4j.Logger; 4 import org.slf4j.LoggerFactory; 5 6 import com.deleba.quartz.service.ILicenseCarrierService; 7 import com.deleba.quartz.utils.SpringUtil; 8 9 /** 10 * 定时任务线程 11 * 12 * @author Administrator 13 * 14 */ 15 public class QuartzThread implements Runnable { 16 17 private Logger logger = LoggerFactory.getLogger(QuartzThread.class); 18 19 @Override 20 public void run() { 21 try { 22 //获取bean 23 IDemoService licenseCarrierService = SpringUtil.getBean(IDemoService.class); 24 //执行任务 25 lDemoService.method(); 26 logger.info("执行成功"); 27 } catch (Exception e) { 28 logger.error("执行失败: " + e.getLocalizedMessage()); 29 } 30 } 31 32 }
由此定时任务线程,没在注入springbean,使用@Autowired获取不到bean,需要写一个获取bean的util来获取springbean
1 package com.deleba.quartz.utils; 2 3 import org.springframework.beans.BeansException; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.ApplicationContextAware; 6 import org.springframework.stereotype.Component; 7 8 /** 9 * 获取bean工具 10 * 11 * @author Administrator 12 * 13 */ 14 @Component 15 public class SpringUtil implements ApplicationContextAware { 16 17 private static ApplicationContext applicationContext; 18 19 @Override 20 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 21 if (SpringUtil.applicationContext == null) { 22 SpringUtil.applicationContext = applicationContext; 23 } 24 } 25 26 // 获取applicationContext 27 public static ApplicationContext getApplicationContext() { 28 return applicationContext; 29 } 30 31 // 通过name获取 Bean. 32 public static Object getBean(String name) { 33 return getApplicationContext().getBean(name); 34 } 35 36 // 通过class获取Bean. 37 public static <T> T getBean(Class<T> clazz) { 38 return getApplicationContext().getBean(clazz); 39 } 40 41 // 通过name,以及Clazz返回指定的Bean 42 public static <T> T getBean(String name, Class<T> clazz) { 43 return getApplicationContext().getBean(name, clazz); 44 } 45 46 }
7.定时任务类
1 package com.deleba.quartz.scheduler; 2 3 import java.util.concurrent.ScheduledFuture; 4 5 import org.slf4j.Logger; 6 import org.slf4j.LoggerFactory; 7 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 8 9 import com.yonyou.mcloud.trigger.McloudTrigger; 10 11 /** 12 * 定时任务 13 * 14 * @author Administrator 15 * 16 */ 17 public class QuartzScheduler { 18 19 private Logger logger = LoggerFactory.getLogger(QuartzScheduler.class); 20 21 private ThreadPoolTaskScheduler threadPoolTaskScheduler; 22 23 private ScheduledFuture<?> scheduledFuture; 24 25 private String cron = "";//事件表达式 26 27 private Runnable runnable;//定时任务 28 29 public McloudScheduler(Runnable runnable, String cron, ThreadPoolTaskScheduler threadPoolTaskScheduler) { 30 super(); 31 this.runnable = runnable; 32 this.cron = cron; 33 this.threadPoolTaskScheduler = threadPoolTaskScheduler; 34 } 35 36 public String getCron() { 37 return cron; 38 } 39 40 /** 41 * 停止定时任务 42 */ 43 public void stop() { 44 if (scheduledFuture != null) { 45 scheduledFuture.cancel(true); 46 } 47 } 48 49 /** 50 * 设置时间表达式 51 * 52 * @param cron 53 */ 54 public void setCron(String cron) { 55 this.cron = cron; 56 stop(); 57 scheduledFuture = threadPoolTaskScheduler.schedule(runnable, new McloudTrigger(cron)); 58 } 59 }
8.定时任务工厂类
1 package com.deleba.quartz.factory; 2 3 import java.util.HashMap; 4 5 import java.util.Map; 6 7 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 8 9 import com.deleba.quartz.scheduler.QuzrtzScheduler; 10 11 /** 12 * 定时任务工厂类 13 * 14 * @author Administrator 15 * 16 */ 17 public class ScheduledFutureFactory { 18 19 private static Map<Integer, QuartzScheduler> map = new HashMap<>(0); 20 21 /** 22 * 获取定时任务实例 23 * 24 * @param cronId 25 * @param runnable 26 * @param cron 27 * @param threadPoolTaskScheduler 28 * @return 29 */ 30 public static QuartzScheduler createQuartzScheduler(Integer cronId, Runnable runnable, String cron, 31 ThreadPoolTaskScheduler threadPoolTaskScheduler) { 32 QuartzScheduler quartzScheduler = new QuartzScheduler(runnable, cron, threadPoolTaskScheduler); 33 map.put(cronId, quartzScheduler); 34 return quartzScheduler; 35 } 36 37 /** 38 * 根据key获取定时任务实例 39 * 40 * @param cronId 41 * @return 42 */ 43 public static QuartzScheduler getQuartzScheduler(Integer cronId) { 44 return map.get(cronId); 45 } 46 47 }
9.controller
1 package com.deleba.quartz.controller; 2 3 import java.util.List; 4 5 import org.apache.commons.lang3.StringUtils; 6 import org.slf4j.Logger; 7 import org.slf4j.LoggerFactory; 8 import org.springframework.beans.factory.annotation.Autowired; 9 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 10 import org.springframework.web.bind.annotation.RequestBody; 11 import org.springframework.web.bind.annotation.RequestMapping; 12 import org.springframework.web.bind.annotation.RequestMethod; 13 import org.springframework.web.bind.annotation.RequestParam; 14 import org.springframework.web.bind.annotation.ResponseBody; 15 import org.springframework.web.bind.annotation.RestController; 16 17 import com.deleba.quartz.common.response.JsonResponse; 18 import com.deleba.quartz.common.response.JsonResponseBuilder; 19 import com.deleba.quartz.entity.CronVO; 20 import com.deleba.quartz.factory.ScheduledFutureFactory; 21 import com.deleba.quartz.scheduler.QuartzScheduler; 22 import com.deleba.quartz.service.ICronService; 23 24 /*** 25 * 定时任务操作--表现层 26 * 27 * @author Administrator 28 * 29 */ 30 @RestController 31 @RequestMapping("/scheduler") 32 public class SchedulerController { 33 34 private Logger logger = LoggerFactory.getLogger(SchedulerController.class); 35 36 @Autowired 37 private ICronService cronService; 38 39 @Autowired 40 private ThreadPoolTaskScheduler threadPoolTaskScheduler; 41 42 /** 43 * 开启定时任务 44 * 45 * @param cronId 46 * @return 47 */ 48 @RequestMapping(value = "/start", method = RequestMethod.GET) 49 @ResponseBody 50 public JsonResponse start(@RequestParam(name = "cronId", defaultValue = "") Integer cronId) { 51 // 1.参数校验 52 CronVO cronVO = cronService.findByCronId(cronId); 53 if (cronVO == null) { 54 return JsonResponseBuilder.buildFailResponse("cronId无效"); 55 } 56 String cron = cronVO.getCron(); 57 String schedulerClass = cronVO.getSchedulerClass(); 58 // 2.开启任务 59 try { 60 Runnable runnable = (Runnable) Class.forName(schedulerClass).newInstance(); 61 QuartzScheduler quartzScheduler = ScheduledFutureFactory.getQuartzScheduler(cronId); 62 if (quartzScheduler == null) { 63 quartzScheduler = ScheduledFutureFactory.createQuartzScheduler(cronId, runnable, cron, 64 threadPoolTaskScheduler); 65 } 66 quartzScheduler.setCron(cron); 67 cronVO.setStatus(1); 68 cronService.update(cronVO); 69 logger.info("开启定时任务成功"); 70 return JsonResponseBuilder.buildSuccessResponse("开启定时任务成功"); 71 } catch (Exception e) { 72 logger.error(e.getMessage(), e); 73 return JsonResponseBuilder.buildFailResponse("开启定时任务失败"); 74 } 75 } 76 77 /** 78 * 关闭定时任务 79 * 80 * @param cronId 81 * @return 82 */ 83 @RequestMapping(value = "/close", method = RequestMethod.GET) 84 @ResponseBody 85 public JsonResponse close(@RequestParam(name = "cronId", defaultValue = "") Integer cronId) { 86 // 1.参数校验 87 CronVO cronVO = cronService.findByCronId(cronId); 88 if (cronVO == null) { 89 return JsonResponseBuilder.buildFailResponse("cronId无效"); 90 } 91 String cron = cronVO.getCron(); 92 String schedulerClass = cronVO.getSchedulerClass(); 93 // 2.关闭任务 94 try { 95 Runnable runnable = (Runnable) Class.forName(schedulerClass).newInstance(); 96 QuartzScheduler quartzScheduler = ScheduledFutureFactory.getQuartzScheduler(cronId); 97 if (mcloudScheduler == null) { 98 quartzScheduler = ScheduledFutureFactory.createQuartzScheduler(cronId, runnable, cron, 99 threadPoolTaskScheduler); 100 } 101 quartzScheduler.stop(); 102 cronVO.setStatus(0); 103 cronService.update(cronVO); 104 logger.info("关闭定时任务成功"); 105 return JsonResponseBuilder.buildSuccessResponse("关闭定时任务成功"); 106 } catch (Exception e) { 107 logger.error(e.getMessage(), e); 108 return JsonResponseBuilder.buildFailResponse("关闭定时任务失败"); 109 } 110 } 111 112 /*** 113 * 更新定时任务 114 * 115 * @param cronVO 116 * @return 117 */ 118 @RequestMapping(value = "/update", method = RequestMethod.POST) 119 @ResponseBody 120 public JsonResponse update(@RequestBody CronVO cronVO) { 121 // 1.参数校验 122 Integer cronId = cronVO.getCronId(); 123 String cron = cronVO.getCron(); 124 Integer status = cronVO.getStatus(); 125 String schedulerClass = cronVO.getSchedulerClass(); 126 if (StringUtils.isBlank(cron) || StringUtils.isBlank(schedulerClass)) { 127 return JsonResponseBuilder.buildFailResponse("时间表达式和定时任务类不可为空"); 128 } 129 try { 130 // 2.更新实体,定时任务开启状态则重新设置表达式 131 cronService.update(cronVO); 132 if (status == 1) { 133 Runnable runnable = (Runnable) Class.forName(schedulerClass).newInstance(); 134 QuartzScheduler quartzScheduler = ScheduledFutureFactory.getQuartzScheduler(cronId); 135 if (mcloudScheduler == null) { 136 mcloudScheduler = ScheduledFutureFactory.createQuartzScheduler(cronId, runnable, cron, 137 threadPoolTaskScheduler); 138 } 139 mcloudScheduler.setCron(cron); 140 } 141 } catch (Exception e) { 142 logger.error(e.getMessage(), e); 143 return JsonResponseBuilder.buildFailResponse("更新定时任务失败"); 144 } 145 logger.info("更新定时任务成功"); 146 return JsonResponseBuilder.buildFailResponse("更新定时任务成功"); 147 } 148 149 /*** 150 * 根据主键获取定时任务相关信息 151 * 152 * @param cronId 153 * @return 154 */ 155 @RequestMapping(value = "/findById", method = RequestMethod.GET) 156 @ResponseBody 157 public CronVO findById(@RequestParam(name = "cronId", defaultValue = "") Integer cronId) { 158 if (cronId == null) { 159 return null; 160 } 161 CronVO cronVO = cronService.findByCronId(cronId); 162 return cronVO; 163 } 164 165 /*** 166 * 获取所有定时任务信息 167 * 168 * @return 169 */ 170 @RequestMapping(value = "/findAll", method = RequestMethod.GET) 171 @ResponseBody 172 public List<CronVO> findAll() { 173 return cronService.findAll(); 174 } 175 }