Spring MVC Quartz 動態任務

一、配置spring-scheduler.xml啓動任務後由這個任務去掃描數據庫,進行動態任務操作

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <!--開啓一個任務掃描任務表動態創建管理等-->
    <bean id="quartzJobManager" class="com.task.job.QuartzJobManager"/>

    <!--  定時任務自動創建任務 -->
    <bean id="arrageScheduleJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="quartzJobManager"/>
        <property name="targetMethod" value="arrageScheduleJob"/>
    </bean>

    <bean id="arrageScheduleJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail">
            <ref bean="arrageScheduleJob"/>
        </property>
        <property name="cronExpression">
            <value>0 */1 * * * ?</value>
        </property>
    </bean>

    <bean id="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="arrageScheduleJobTrigger"/>
            </list>
        </property>
        <property name="taskExecutor" ref="executor"/>
    </bean>
    <bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="10"/>
        <property name="maxPoolSize" value="100"/>
        <property name="queueCapacity" value="500"/>
    </bean>
</beans>

spring-context.xml

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--掃描service-->
    <context:component-scan base-package="com.task.service.impl"/>

    <!-- 定時任務 -->
    <import resource="spring-scheduler.xml"/>

</beans>

spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">

    <!--是一種簡寫形式,完全可以手動配置替代這種簡寫形式,簡寫形式可以讓初學都快速應用默認配置方案。
     會自動註冊DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter 兩個bean,
     是spring MVC爲@Controllers分發請求所必須的。
     並提供了:數據綁定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,讀寫XML的支持(JAXB),讀寫JSON的支持(Jackson)。-->
    <mvc:annotation-driven/>

    <!--掃描controller-->
    <context:component-scan base-package="com.task.controller"/>

    <!-- 視圖解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前綴 -->
        <property name="prefix">
            <value>/WEB-INF/JSP/</value>
        </property>
        <!-- 後綴 -->
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

    <!-- spring mvc 上傳文件 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
          p:maxUploadSize="512000000" p:maxInMemorySize="512000000" p:defaultEncoding="UTF-8"/>
    <mvc:default-servlet-handler/>

</beans>

pom.xml

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.task</groupId>
    <artifactId>AutoTask</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>AutoTask Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <properties>
        <spring.version>5.0.4.RELEASE</spring.version>
        <quartz.version>2.3.0</quartz.version>
        <sqlite.version>3.21.0.1</sqlite.version>
        <fileupload.version>1.3.3</fileupload.version>
        <slf4j.version>1.8.0-beta1</slf4j.version>
        <jackson.version>2.9.4</jackson.version>
    </properties>
    <dependencies>
        <!--SPRING依賴-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>


        <!--文件上傳依賴-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>${fileupload.version}</version>
        </dependency>

        <!--常用工具類,比如StringUtil-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>

        <!--gson json工具類-->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.2</version>
        </dependency>


        <!--定時任務依賴-->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>${quartz.version}</version>
        </dependency>

        <!--SQLLITE驅動-->
        <dependency>
            <groupId>org.xerial</groupId>
            <artifactId>sqlite-jdbc</artifactId>
            <version>${sqlite.version}</version>
        </dependency>

        <!--日誌依賴-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

        <!--@ResponseBody 依賴-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>AutoTask</finalName>
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.8.v20171121</version>
                <configuration>
                    <webAppConfig>
                        <contextPath>/</contextPath>
                        <webInfIncludeJarPattern>.*/foo-[^/]*\.jar$|.*/classes/.*</webInfIncludeJarPattern>
                    </webAppConfig>
                    <httpConnector>
                        <port>9999</port>
                        <idleTimeout>10000</idleTimeout>
                    </httpConnector>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

二、主要類

package com.task.job;

import java.io.Serializable;

/**
 * 對應的表<schedule_job>
 */
public class ScheduleJob implements Serializable {
    private static final long serialVersionUID = -6268330198581041868L;

    private String jobId;//任務ID
    private String jobName;//任務名稱
    private String jobGroup;//任務分組
    private int jobStatus;//任務狀態 0啓用 1禁用 2刪除
    private String cronExpression;//任務運行時間表達式
    private String description;//任務描述
    private String targetObject;//任務類名
    private String targetMethod;//任務方法名
    private int isSpringBean;//是否是Spring中定義的Bean 0 是  1 不是
    private String clazz;//如果isSpringBean = 1  需要設置全類名,測試CLAZZ字段需要配置
    private int concurrent;// 是否併發 0啓用  1禁用

    public String getJobId() {
        return jobId;
    }

    public void setJobId(String jobId) {
        this.jobId = jobId;
    }

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public String getJobGroup() {
        return jobGroup;
    }

    public void setJobGroup(String jobGroup) {
        this.jobGroup = jobGroup;
    }

    public int getJobStatus() {
        return jobStatus;
    }

    public void setJobStatus(int jobStatus) {
        this.jobStatus = jobStatus;
    }

    public String getCronExpression() {
        return cronExpression;
    }

    public void setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getTargetObject() {
        return targetObject;
    }

    public void setTargetObject(String targetObject) {
        this.targetObject = targetObject;
    }

    public String getTargetMethod() {
        return targetMethod;
    }

    public void setTargetMethod(String targetMethod) {
        this.targetMethod = targetMethod;
    }

    public int getIsSpringBean() {
        return isSpringBean;
    }

    public void setIsSpringBean(int isSpringBean) {
        this.isSpringBean = isSpringBean;
    }

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }

    public int getConcurrent() {
        return concurrent;
    }

    public void setConcurrent(int concurrent) {
        this.concurrent = concurrent;
    }

    @Override
    public String toString() {
        return "ScheduleJob{" +
                "jobId='" + jobId + '\'' +
                ", jobName='" + jobName + '\'' +
                ", jobGroup='" + jobGroup + '\'' +
                ", jobStatus=" + jobStatus +
                ", cronExpression='" + cronExpression + '\'' +
                ", description='" + description + '\'' +
                ", targetObject='" + targetObject + '\'' +
                ", targetMethod='" + targetMethod + '\'' +
                ", isSpringBean=" + isSpringBean +
                ", clazz='" + clazz + '\'' +
                ", concurrent=" + concurrent +
                '}';
    }
}
package com.task.job;


import com.task.service.ScheduleJobService;
import com.task.util.SpringContextUtil;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;

import javax.annotation.Resource;
import java.util.List;

/**
 * 動態生成定時任務
 */
public class QuartzJobManager {

    private static final Logger log = LogManager.getLogger(QuartzJobManager.class);

    @Resource
    private Scheduler scheduler;

    @Resource
    private ScheduleJobService scheduleJobService;

    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    /**
     * <p>
     * 掃描數據庫,查看是否有計劃任務的變動
     * <p>
     *
     * @Date 2018年3月22日
     * @author Adam.Fei
     */
    public void arrageScheduleJob() {
        try {
            List<ScheduleJob> jobList = scheduleJobService.getScheduleJobs();
            if (jobList.size() != 0) {
                for (ScheduleJob job : jobList) {
                    //triggerKey 由名稱和分組組成,組中的名稱必須唯一
                    TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
                    // 獲取trigger(時間觸發器)
                    CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                    // 不存在,創建一個
                    if (null == trigger) {
                        createSheduler(scheduler, job);
                    } else {
                        // Trigger已存在,那麼更新相應的定時設置
                        updateScheduler(scheduler, job, triggerKey, trigger);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * <p>
     * 更新相應的定時設置 根據job_status做相應的處理
     * <p>
     *
     * @param scheduler  定時任務調度器
     * @param job        定時任務數據
     * @param triggerKey 定時任務key
     * @param trigger    時間觸發器
     * @throws SchedulerException
     * @Date 2018年3月22日
     * @author wlx
     */
    private void updateScheduler(Scheduler scheduler, ScheduleJob job, TriggerKey triggerKey, CronTrigger trigger)
            throws SchedulerException {
        switch (job.getJobStatus()) {
            case 0://啓用狀態
                if (!trigger.getCronExpression().equalsIgnoreCase(job.getCronExpression())) {
                    // 表達式調度構建器
                    CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
                    // 按新的cronExpression表達式重新構建trigger
                    trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                    // 按新的trigger重新設置job執行
                    scheduler.rescheduleJob(triggerKey, trigger);
                    log.info(job.getJobGroup() + "." + job.getJobName() + " 更新完畢,目前cron表達式爲:" + job.getCronExpression()
                            + " isSpringBean:" + job.getIsSpringBean() + " concurrent: " + job.getConcurrent());
                }
                break;
            case 1://停用狀態
                scheduler.pauseTrigger(triggerKey);// 停止觸發器
                scheduler.unscheduleJob(triggerKey);// 移除觸發器
                scheduler.deleteJob(trigger.getJobKey());// 刪除任務
                log.info(job.getJobGroup() + "." + job.getJobName() + "刪除完畢");
                break;
            default:
                log.error(job.getJobStatus() + "狀態未處理!");
        }
    }

    /**
     * <p>
     * 創建一個定時任務,並做安排
     * <p>
     *
     * @param scheduler 定時任務調度器
     * @param job       定時任務數據
     * @throws Exception
     * @Date 2018年3月22日
     * @author wlx
     */
    public void createSheduler(Scheduler scheduler, ScheduleJob job) throws Exception {
        // 在工作狀態可用時,即job_status = 0 ,開始創建
        if (job.getJobStatus() == 0) {
            // 新建一個基於Spring的管理Job類
            MethodInvokingJobDetailFactoryBean methodInvJobDetailFB = new MethodInvokingJobDetailFactoryBean();
            // 設置Job名稱
            methodInvJobDetailFB.setName(job.getJobName());
            // 定義的任務類爲Spring的定義的Bean則調用 getBean方法
            if (job.getIsSpringBean() == 0) {// 是Spring中定義的Bean
                methodInvJobDetailFB.setTargetObject(SpringContextUtil.getApplicationContext().getBean(job.getTargetObject()));
            } else {// 不是
                Object object = Class.forName(job.getClazz()).newInstance();
                capableBeanFactory.autowireBean(object);
                methodInvJobDetailFB.setTargetObject(object);
            }
            // 設置任務方法
            methodInvJobDetailFB.setTargetMethod(job.getTargetMethod());
            // 將管理Job類提交到計劃管理類
            methodInvJobDetailFB.afterPropertiesSet();
            /** 併發設置 */
            methodInvJobDetailFB.setConcurrent(job.getConcurrent() == 0 ? true : false);

            JobDetail jobDetail = methodInvJobDetailFB.getObject();// 動態
            jobDetail.getJobDataMap().put("scheduleJob", job);

            // 表達式調度構建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            // 按新的cronExpression表達式構建一個新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup())
                    .withSchedule(scheduleBuilder).build();

            scheduler.scheduleJob(jobDetail, trigger);// 注入到管理類
            log.info(job.getJobGroup() + "." + job.getJobName() + "創建完畢");
        }
    }
}

package com.task.service;

import com.task.job.ScheduleJob;

import java.util.List;

public interface ScheduleJobService {
    List<ScheduleJob> getScheduleJobs();
}
package com.task.service.impl;

import com.task.job.ScheduleJob;
import com.task.service.ScheduleJobService;
import com.task.util.SqliteUtil;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.util.List;

@Service("scheduleJobService")
public class ScheduleJobServiceImpl implements ScheduleJobService {
    public List<ScheduleJob> getScheduleJobs() {
        Connection connection = SqliteUtil.getConnection();
        SqliteUtil.initTable(connection);
        List<ScheduleJob> list = SqliteUtil.getJobDate(connection);
        SqliteUtil.closeConnection(connection);
        return list;
    }
}

三、源碼下載

https://download.csdn.net/download/w13511069150/10303711





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章