利用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&amp;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

posted @ 2017-11-06 16:35  小不点丶  阅读(22533)  评论(0编辑  收藏  举报