利用quartz实现定时调度
1、Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。这里我介绍quartz的两种方式。我这里搭建的框架是采用springboot、spring-data-jpa、mysql、quartz的方式来实现。
2、这里介绍的两种方式是:动态扫描的方式执行和注解的方式。
至于xml的配置方式可以参考:http://www.cnblogs.com/ll409546297/p/7157702.html
3、动态扫描的方式
1)基本的目录结构
2)需要的基础包:pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.troy</groupId> <artifactId>springbootquartz</artifactId> <version>1.0-SNAPSHOT</version> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.7.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>1.5.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>1.5.7.RELEASE</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.9</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.11.RELEASE</version> </dependency> </dependencies> </project>
3)基本的yml配置application.yml
server: port: 8080 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/model?useUnicode=true&characterEncoding=utf8 username: root password: root jpa: hibernate: ddl-auto: update show-sql: true
4)任务配置:TaskConfiguration.class
@Configuration @EnableScheduling public class TaskConfiguration { @Bean public SchedulerFactoryBean schedulerFactoryBean(){ return new SchedulerFactoryBean(); } }
5)实体需要的基础配置:ScheduleJob.class
@Entity @Table public class ScheduleJob { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String jobName; private String cronExpression; private String springId; private String methodName; private String jobStatus; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getJobName() { return jobName; } public void setJobName(String jobName) { this.jobName = jobName; } public String getCronExpression() { return cronExpression; } public void setCronExpression(String cronExpression) { this.cronExpression = cronExpression; } public String getSpringId() { return springId; } public void setSpringId(String springId) { this.springId = springId; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public String getJobStatus() { return jobStatus; } public void setJobStatus(String jobStatus) { this.jobStatus = jobStatus; } }
6)基础数据访问配置和数据访问层:
@NoRepositoryBean public interface BaseRepository<T,I extends Serializable> extends PagingAndSortingRepository<T,I>, JpaSpecificationExecutor<T> { }
public interface ScheduleJobRepository extends BaseRepository<ScheduleJob,Long> { List<ScheduleJob> findAllByJobStatus(String jobStatus); }
7)SpringUtil.class
@Component public class SpringUtil implements BeanFactoryPostProcessor { private static ConfigurableListableBeanFactory beanFactory; public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } public static Object getBean(String name) { return beanFactory.getBean(name); } public static <T> T getBean(Class<T> clazz){ return beanFactory.getBean(clazz); } }
8)任务的调度工厂(主要是实现具体的执行)QuartzFactory.class
public class QuartzFactory implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //获取调度数据 ScheduleJob scheduleJob = (ScheduleJob) jobExecutionContext.getMergedJobDataMap().get("scheduleJob"); //获取对应的Bean Object object = SpringUtil.getBean(scheduleJob.getSpringId()); try { //利用反射执行对应方法 Method method = object.getClass().getMethod(scheduleJob.getMethodName()); method.invoke(object); } catch (Exception e) { e.printStackTrace(); } } }
9)具体的任务调度以及触发设置:TaskServiceImpl.class(略过接口)
@Service @Transactional public class TaskServiceImpl implements ITaskService { @Autowired private SchedulerFactoryBean schedulerFactoryBean; @Autowired private ScheduleJobRepository scheduleJobRepository; @Override public void timingTask() { //查询数据库是否存在需要定时的任务 List<ScheduleJob> scheduleJobs = scheduleJobRepository.findAllByJobStatus("1"); if (scheduleJobs != null) { scheduleJobs.forEach(this::execute); } } //添加任务 private void execute(ScheduleJob scheduleJob){ try { //声明调度器 Scheduler scheduler = schedulerFactoryBean.getScheduler(); //添加触发调度名称 TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName()); //设置触发时间 CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()); //触发建立 Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build(); //添加作业名称 JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName()); //建立作业 JobDetail jobDetail = JobBuilder.newJob(QuartzFactory.class).withIdentity(jobKey).build(); //传入调度的数据,在QuartzFactory中需要使用 jobDetail.getJobDataMap().put("scheduleJob",scheduleJob); //调度作业 scheduler.scheduleJob(jobDetail,trigger); } catch (Exception e) { throw new RuntimeException(e); } } }
10)然后设置开机启动执行:TaskSchedule.class
@Component public class TaskSchedule implements CommandLineRunner{ @Autowired private ITaskService taskService; /** * 任务调度开始 * @param strings * @throws Exception */ @Override public void run(String... strings) throws Exception { System.out.println("任务调度开始==============任务调度开始"); taskService.timingTask(); System.out.println("任务调度结束==============任务调度结束"); } }
这里基础的配置就算完成了,然后就是在数据库进行相关的配置,项目启动的时候就开始扫描对应的表来执行具体的任务。
这里我写了一下简单的例子来实现。
1)需要执行的方法:TaskInfoServiceImpl.class(略过接口)
@Service("taskInfo") @Transactional public class TaskInfoServiceImpl implements ITaskInfoService { @Override public void execute() { System.out.println("任务执行开始===============任务执行开始"); System.out.println(new Date()); System.out.println("任务执行结束===============任务执行结束"); } }
2)数据库的配置(我这里测试用的每分钟0点执行)
测试结果:
4、注解的方式
1)注解的方式相对动态配置来说简单的多,但是不便于管理。注解的方式需要的基础包,和上面基本上差不多
2)这里我写了一下简单的例子来实现:TaskExcuteServiceImpl.class
@Service @Transactional public class TaskExcuteServiceImpl implements ITaskExcuteService { @Scheduled(cron = "30 * * * * ?") @Override public void excute() { System.out.println("注解执行开始==============注解执行开始"); System.out.println(new Date()); System.out.println("注解执行结束==============注解执行结束"); } }
3)测试结果为:
5、有需要源码的可以自己下载:https://pan.baidu.com/s/1pLSLdTT