1. 程式人生 > >spring boot2 整合(四)定時任務Scheduled || Quartz並持久化

spring boot2 整合(四)定時任務Scheduled || Quartz並持久化

在進入正文前,我想把所有java可以實現的定時任務介紹一下,其實這個也是底層實現思路。

本教程大概目錄:
1. 執行緒等待實現定時任務
2. 用Timer實現定時任務
3. 用ScheduledExecutorService實現定時任務
4. Quartz 定時任務框架單機應用
5. spingboot2 整合 Scheduled
6. spingboot2 整合 Quartz框架持久化定時任務

1. 執行緒等待實現定時任務

package com.fantj.myScheduled;

/**
 * Created by Fant.J.
 */
public class
Test {
public static void main(String[] args) { Thread thread = new Thread(()->{ while (true) { System.out.println("假設我是個定時任務"); try { Thread.sleep(1000 * 10); //執行緒休息十秒 } catch (InterruptedException e) { e.printStackTrace(); } } }); } }

大家看程式碼也能看出來,如果任務複雜時,是相當的麻煩,而且還存在記憶體洩露風險,而且是一發不可收拾(不可控)。

下面看一個相對簡單的。

2. Timer

package com.fantj.myScheduled;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by Fant.J.
 */
public class Test {
    public static void main(String[] args) {

        TimerTask task = new TimerTask() {
            @Override
public void run() { System.out.println("TimerTask is called!"); } }; Timer timer = new Timer(); /* * 引數:1、任務體 2、延時時間(可以指定執行日期)3、任務執行間隔時間 */ timer.schedule(task, 0, 1000 * 3); timer.scheduleAtFixedRate(task, 0, 1000 * 3); } }

注意上面timer呼叫的兩個方法:
1、schedule,如果第一次執行被延時,隨後的任務執行時間將以上一次任務實際執行完成的時間為準
2、scheduleAtFixedRate,如果第一次執行被延時,隨後的任務執行時間將以上一次任務開始執行的時間為準(需考慮同步)

如果讓我粗俗的講,第一個是等任務進行完了才開始計時,第二個是任務開始執行的時候就計時。

那我們稍微瞄一眼 Timer底層實現

public void schedule(TimerTask task, Date firstTime, long period) {
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, firstTime.getTime(), -period);
    }

然後看看TimerTask類

public abstract class TimerTask implements Runnable {
      public abstract void run();
    ...
}

大概也能看出來,也是執行緒實現。

Timer也有缺點:

多執行緒並行處理定時任務時,Timer執行多個TimeTask時,只要其中之一沒有捕獲丟擲的異常,其它任務便會自動終止執行,使用ScheduledExecutorService則沒有這個問題。

3. 那我們就來研究ScheduledExecutorService

package com.fantj.myScheduled;

/**
 * Created by Fant.J.
 */
public class Test {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("ScheduledExecutorService Task is called!");
            }
        };
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        // 引數:1、任務體 2、首次執行的延時時間
        //      3、任務執行間隔 4、間隔時間單位
        service.scheduleAtFixedRate(runnable, 0, 3, TimeUnit.SECONDS);
    }
}

這個。。就不多說實現原理了Executors執行緒池都出現了。

Quartz 定時任務框架

為什麼會有定時任務框架呢,大家仔細觀察前面的實現案例,沒有一個定時任務是可控的,這對開發者來說特別不友好。Quartz就比較nb了,我帶大家稍微看看它的一部分方法:
我先大概介紹下Quartz工作原理,JobDetail是寫定時任務邏輯,Trigger是一個觸發器,用來定義cron和執行次數等。

    String getSchedulerName() throws SchedulerException;

    String getSchedulerInstanceId() throws SchedulerException;

    SchedulerContext getContext() throws SchedulerException;

    void start() throws SchedulerException;

    void startDelayed(int var1) throws SchedulerException;

    boolean isStarted() throws SchedulerException;

    void standby() throws SchedulerException;

    boolean isInStandbyMode() throws SchedulerException;

    void shutdown() throws SchedulerException;

    void shutdown(boolean var1) throws SchedulerException;

    boolean isShutdown() throws SchedulerException;

    SchedulerMetaData getMetaData() throws SchedulerException;

    List<JobExecutionContext> getCurrentlyExecutingJobs() throws SchedulerException;

    void setJobFactory(JobFactory var1) throws SchedulerException;

    ListenerManager getListenerManager() throws SchedulerException;

    Date scheduleJob(JobDetail var1, Trigger var2) throws SchedulerException;

    Date scheduleJob(Trigger var1) throws SchedulerException;

    void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> var1, boolean var2) throws SchedulerException;

    void scheduleJob(JobDetail var1, Set<? extends Trigger> var2, boolean var3) throws SchedulerException;

    boolean unscheduleJob(TriggerKey var1) throws SchedulerException;

    boolean unscheduleJobs(List<TriggerKey> var1) throws SchedulerException;

    Date rescheduleJob(TriggerKey var1, Trigger var2) throws SchedulerException;

    void addJob(JobDetail var1, boolean var2) throws SchedulerException;

    void addJob(JobDetail var1, boolean var2, boolean var3) throws SchedulerException;

    boolean deleteJob(JobKey var1) throws SchedulerException;

    boolean deleteJobs(List<JobKey> var1) throws SchedulerException;

    void triggerJob(JobKey var1) throws SchedulerException;

    void triggerJob(JobKey var1, JobDataMap var2) throws SchedulerException;

    void pauseJob(JobKey var1) throws SchedulerException;

    void pauseJobs(GroupMatcher<JobKey> var1) throws SchedulerException;

    void pauseTrigger(TriggerKey var1) throws SchedulerException;

    void pauseTriggers(GroupMatcher<TriggerKey> var1) throws SchedulerException;

    void resumeJob(JobKey var1) throws SchedulerException;

    void resumeJobs(GroupMatcher<JobKey> var1) throws SchedulerException;

    void resumeTrigger(TriggerKey var1) throws SchedulerException;

    void resumeTriggers(GroupMatcher<TriggerKey> var1) throws SchedulerException;

    void pauseAll() throws SchedulerException;

    void resumeAll() throws SchedulerException;

    List<String> getJobGroupNames() throws SchedulerException;

    Set<JobKey> getJobKeys(GroupMatcher<JobKey> var1) throws SchedulerException;

    List<? extends Trigger> getTriggersOfJob(JobKey var1) throws SchedulerException;

    List<String> getTriggerGroupNames() throws SchedulerException;

    Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> var1) throws SchedulerException;

    Set<String> getPausedTriggerGroups() throws SchedulerException;

    JobDetail getJobDetail(JobKey var1) throws SchedulerException;

    TriggerState getTriggerState(TriggerKey var1) throws SchedulerException;

    void resetTriggerFromErrorState(TriggerKey var1) throws SchedulerException;

    boolean interrupt(String var1) throws UnableToInterruptJobException;

    boolean checkExists(JobKey var1) throws SchedulerException;

可以看到,基本上對定時任務的控制可以說是很全了。包括增刪改查等。
下面是個例項,當然,你需要下載必要的依賴jar,這個可以自行百度下載一下,不做重點解釋。

package com.fantj.myScheduled;

/**
 * Created by Fant.J.
 */
public class Test {
    public static void main(String[] args) {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.start();

            JobDetail job = JobBuilder.newJob(Job.class)
                    .withIdentity("job", "group").build();

            // 休眠時長可指定時間單位,此處使用秒作為單位(withIntervalInSeconds)
            SimpleTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger", "group").startNow()
                    .withSchedule(simpleSchedule().withIntervalInSeconds(3).repeatForever())
                    .build();

            scheduler.scheduleJob(job, trigger);

            // scheduler.shutdown();

        } catch (SchedulerException se) {
            se.printStackTrace();
        }
    }
}

    class Job implements org.quartz.Job {
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            System.out.println("Quartz task is called!");
        }
}

spingboot2 整合 Scheduled

SpringBoot內建了定時任務Scheduled,操作可謂特別簡單。
正常引入spring-boot-starter-web依賴包即可實現。

Scheduled 第一步

再啟動類上添加註解@EnableScheduling

package com.fantj;

@SpringBootApplication
@MapperScan("com.fantj.mapper")
@EnableScheduling  //啟動定時任務
public class MybatisApplication {

    public static void main(String[] args) {
        SpringApplication.run(MybatisApplication.class, args);
    }
}
Scheduled 第二步

寫Task。即定時任務。

package com.fantj.myScheduled;

/**
 * scheduled 定時任務類
 * Created by Fant.J.
 */
@Component
public class Task {


    @Scheduled(cron = "5 0 0 * * ?")
    public void scheduledTask1(){
        System.out.println("scheduledTask method run..");
    }

    @Scheduled(initialDelay =  1000 * 10,fixedDelay = 1000 * 5)
    public void scheduledTask2(){
        System.out.println("scheduledTask method run..");
    }

    @Scheduled(initialDelay =  1000 * 10,fixedDelay = 1000 * 5)
    public void test() throws Exception {
        for (int i = 0;i<20;i++){
            new MailSender()
                    .title("FantJ給你傳送的郵件")
                    .content("嘻嘻")
                    .contentType(MailContentTypeEnum.TEXT)
                    .targets(new ArrayList<String>(){{
                        add("[email protected]");
                    }})
                    .send();
            System.out.println("第"+i+"次傳送成功!");
        }
    }
}

第三個方法是我寫的發郵件的一個介面。可以參考我的一篇文章Java 傳送qq郵件

我介紹下@Scheduled註解的三(四)個屬性:
  • cron: 懂點linux的都知道,沒聽說過的可以自己百度一下,不難。

  • fixedRate和fixedDelay: 這和Timer的兩個方法(rate和delay)很相似,如果讓我粗俗的講,第一個是任務開始執行的時候就計時,第二個是等任務進行完了才開始計時。

  • initialDelay:該屬性的作用是 設定第一次執行延遲時間 。需要配合fixedDelay、fixedRate、crom來使用。

新問題的思考

雖然上面的方式一直在改進,但是試想一種情況,如果正在執行定時任務的伺服器掛掉,那該如何去尋找它之前執行了多少次呢。如果我們把定時任務持久化到資料庫,像維護普通邏輯資料那樣維護任務,就會避免專案中遇到的種種的特殊情況。

spingboot2 整合 Quartz框架持久化定時任務

提前宣告啊,很麻煩,因為需要加入ioc管理(有部分註釋,可嘗試看懂),還需要建立quartz需要讓我們建立的資料表。
之後就像玩單機(見上文:Quartz 定時任務框架單機應用)一樣,玩quartz了。

1. 匯入依賴
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
2. Quartz 注入Spring IOC配置

QuartzConfiguration.java

package com.fantj.quartz;

/**
 * quartz定時任務配置
 * Created by Fant.J.
 */
@Configuration
@EnableScheduling
public class QuartzConfiguration
{
    /**
     * 繼承org.springframework.scheduling.quartz.SpringBeanJobFactory
     * 實現任務例項化方式
     */
    public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
            ApplicationContextAware {

        private transient AutowireCapableBeanFactory beanFactory;

        @Override
        public void setApplicationContext(final ApplicationContext context) {
            beanFactory = context.getAutowireCapableBeanFactory();
        }

        /**
         * 將job例項交給spring ioc託管
         * 我們在job例項實現類內可以直接使用spring注入的呼叫被spring ioc管理的例項
         * @param bundle
         * @return
         * @throws Exception
         */
        @Override
        protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
            final Object job = super.createJobInstance(bundle);
            /**
             * 將job例項交付給spring ioc
             */
            beanFactory.autowireBean(job);
            return job;
        }
    }

    /**
     * 配置任務工廠例項
     * @param applicationContext spring上下文例項
     * @return
     */
    @Bean
    public JobFactory jobFactory(ApplicationContext applicationContext)
    {
        /**
         * 採用自定義任務工廠 整合spring例項來完成構建任務
         * see {@link AutowiringSpringBeanJobFactory}
         */
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }

    /**
     * 配置任務排程器
     * 使用專案資料來源作為quartz資料來源
     * @param jobFactory 自定義配置任務工廠
     * @param dataSource 資料來源例項
     * @return
     * @throws Exception
     */
    @Bean(destroyMethod = "destroy",autowire = Autowire.NO)
    public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, DataSource dataSource) throws Exception
    {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        //將spring管理job自定義工廠交由排程器維護
        schedulerFactoryBean.setJobFactory(jobFactory);
        //設定覆蓋已存在的任務
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        //專案啟動完成後,等待2秒後開始執行排程器初始化
        schedulerFactoryBean.setStartupDelay(2);
        //設定排程器自動執行
        schedulerFactoryBean.setAutoStartup(true);
        //設定資料來源,使用與專案統一資料來源
        schedulerFactoryBean.setDataSource(dataSource);
        //設定上下文spring bean name
        schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
        //設定配置檔案位置
        schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));
        return schedulerFactoryBean;
    }
}

看程式碼倒數第二行,需要一個配置檔案,那麼…

quartz.properties配置
#排程器例項名稱
org.quartz.scheduler.instanceName = quartzScheduler

#排程器例項編號自動生成
org.quartz.scheduler.instanceId = AUTO

#持久化方式配置
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX

#持久化方式配置資料驅動,MySQL資料庫
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

#quartz相關資料表字首名
org.quartz.jobStore.tablePrefix = QRTZ_

#開啟分散式部署
org.quartz.jobStore.isClustered = true
#配置是否使用
org.quartz.jobStore.useProperties = false

#分散式節點有效性檢查時間間隔,單位:毫秒
org.quartz.jobStore.clusterCheckinInterval = 20000

#執行緒池實現類
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool

#執行最大併發執行緒數量
org.quartz.threadPool.threadCount = 10

#執行緒優先順序
org.quartz.threadPool.threadPriority = 5

#配置為守護執行緒,設定後任務將不會執行
#org.quartz.threadPool.makeThreadsDaemons=true

#配置是否啟動自動載入資料庫內的定時任務,預設true
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
建立資料表

說出來你可能不信,它需要十一個數據表的支援。

#  
# In your Quartz properties file, you'll need to set   
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate  
#  
#  
# By: Ron Cordell - roncordell  
#  I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM.  

DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;  
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;  
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;  
DROP TABLE IF EXISTS QRTZ_LOCKS;  
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;  
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;  
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;  
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;  
DROP TABLE IF EXISTS QRTZ_TRIGGERS;  
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;  
DROP TABLE IF EXISTS QRTZ_CALENDARS;  

CREATE TABLE QRTZ_JOB_DETAILS(  
SCHED_NAME VARCHAR(120) NOT NULL,  
JOB_NAME VARCHAR(200) NOT NULL,  
JOB_GROUP VARCHAR(200) NOT NULL,  
DESCRIPTION VARCHAR(250) NULL,  
JOB_CLASS_NAME VARCHAR(250) NOT NULL,  
IS_DURABLE VARCHAR(1) NOT NULL,  
IS_NONCONCURRENT VARCHAR(1) NOT NULL,  
IS_UPDATE_DATA VARCHAR(1) NOT NULL,  
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,  
JOB_DATA BLOB NULL,  
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))  
ENGINE=InnoDB;  

CREATE TABLE QRTZ_TRIGGERS (  
SCHED_NAME VARCHAR(120) NOT NULL,  
TRIGGER_NAME VARCHAR(200) NOT NULL,  
TRIGGER_GROUP VARCHAR(200) NOT NULL,  
JOB_NAME VARCHAR(200) NOT NULL,  
JOB_GROUP VARCHAR(200) NOT NULL,  
DESCRIPTION VARCHAR(250) NULL,  
NEXT_FIRE_TIME BIGINT(13) NULL,  
PREV_FIRE_TIME BIGINT(13) NULL,  
PRIORITY INTEGER NULL,  
TRIGGER_STATE VARCHAR(16) NOT NULL,  
TRIGGER_TYPE VARCHAR(8) NOT NULL,  
START_TIME BIGINT(13) NOT NULL,  
END_TIME BIGINT(13) NULL,  
CALENDAR_NAME VARCHAR(200) NULL,  
MISFIRE_INSTR SMALLINT(2) NULL,  
JOB_DATA BLOB NULL,  
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)  
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))  
ENGINE=InnoDB;  

CREATE TABLE QRTZ_SIMPLE_TRIGGERS (  
SCHED_NAME VARCHAR(120) NOT NULL,  
TRIGGER_NAME VARCHAR(200) NOT NULL,  
TRIGGER_GROUP VARCHAR(200) NOT NULL,  
REPEAT_COUNT BIGINT(7) NOT NULL,  
REPEAT_INTERVAL BIGINT(12) NOT NULL,  
TIMES_TRIGGERED BIGINT(10) NOT NULL,  
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)  
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
ENGINE=InnoDB;  

CREATE TABLE QRTZ_CRON_TRIGGERS (  
SCHED_NAME VARCHAR(120) NOT NULL,  
TRIGGER_NAME VARCHAR(200) NOT NULL,  
TRIGGER_GROUP VARCHAR(200) NOT NULL,  
CRON_EXPRESSION VARCHAR(120) NOT NULL,  
TIME_ZONE_ID VARCHAR(80),  
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)  
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
ENGINE=InnoDB;  

CREATE TABLE QRTZ_SIMPROP_TRIGGERS  
  (            
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    STR_PROP_1 VARCHAR(512) NULL,  
    STR_PROP_2 VARCHAR(512) NULL,  
    STR_PROP_3 VARCHAR(512) NULL,  
    INT_PROP_1 INT NULL,  
    INT_PROP_2 INT NULL,  
    LONG_PROP_1 BIGINT NULL,  
    LONG_PROP_2 BIGINT NULL,  
    DEC_PROP_1 NUMERIC(13,4) NULL,  
    DEC_PROP_2 NUMERIC(13,4) NULL,  
    BOOL_PROP_1 VARCHAR(1) NULL,  
    BOOL_PROP_2 VARCHAR(1) NULL,  
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)   
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
ENGINE=InnoDB;  

CREATE TABLE QRTZ_BLOB_TRIGGERS (  
SCHED_NAME VARCHAR(120) NOT NULL,  
TRIGGER_NAME VARCHAR(200) NOT NULL,  
TRIGGER_GROUP VARCHAR(200) NOT NULL,  
BLOB_DATA BLOB NULL,  
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),  
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)  
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
ENGINE=InnoDB;  

CREATE TABLE QRTZ_CALENDARS (  
SCHED_NAME VARCHAR(120) NOT NULL,  
CALENDAR_NAME VARCHAR(200) NOT NULL,  
CALENDAR BLOB NOT NULL,  
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))  
ENGINE=InnoDB;  

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (  
SCHED_NAME VARCHAR(120) NOT NULL,  
TRIGGER_GROUP VARCHAR(200) NOT NULL,  
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))  
ENGINE=InnoDB;  

CREATE TABLE QRTZ_FIRED_TRIGGERS (  
SCHED_NAME VARCHAR(120) NOT NULL,  
ENTRY_ID VARCHAR(95) NOT NULL,  
TRIGGER_NAME VARCHAR(200) NOT NULL,  
TRIGGER_GROUP VARCHAR(200) NOT NULL,  
INSTANCE_NAME VARCHAR(200) NOT NULL,  
FIRED_TIME BIGINT(13) NOT NULL,  
SCHED_TIME BIGINT(13) NOT NULL,  
PRIORITY INTEGER NOT NULL,  
STATE VARCHAR(16) NOT NULL,  
JOB_NAME VARCHAR(200) NULL,  
JOB_GROUP VARCHAR(200) NULL,  
IS_NONCONCURRENT VARCHAR(1) NULL,  
REQUESTS_RECOVERY VARCHAR(1) NULL,  
PRIMARY KEY (SCHED_NAME,ENTRY_ID))  
ENGINE=InnoDB;  

CREATE TABLE QRTZ_SCHEDULER_STATE (  
SCHED_NAME VARCHAR(120) NOT NULL,  
INSTANCE_NAME VARCHAR(200) NOT NULL,  
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,  
CHECKIN_INTERVAL BIGINT(13) NOT NULL,  
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))  
ENGINE=InnoDB;  

CREATE TABLE QRTZ_LOCKS (  
SCHED_NAME VARCHAR(120) NOT NULL,  
LOCK_NAME VARCHAR(40) NOT NULL,  
PRIMARY KEY (SCHED_NAME,LOCK_NAME))  
ENGINE=InnoDB;  

CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);  
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);  

CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);  
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);  
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);  
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);  
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);  
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);  
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);  
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);  
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);  
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);  
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);  
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);  

CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);  
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);  
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);  
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);  
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);  
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);  

commit;   

好了,開始寫定時任務業務

首先我們需要自定義一個Job的子類來寫JobDetail

package com.fantj.quartz.notSpringFrame;

/**
 * quartz增刪改查方法
 */
public class MyJob implements Job {

    public MyJob(){}
    @Override
    //把要執行的操作,寫在execute方法中
    public void execute(JobExecutionContext arg0) throws JobExecutionException
    {
        DateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        System.out.println("測試Quartz"+ df.format(Calendar.getInstance().getTime()));
    }
}

其次,我在這裡演示 如何再 ServiceImpl 裡注入並使用 定時任務。

package com.fantj.service.impl;

/**
 * Created by Fant.J.
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    // 注入任務排程器
  @Autowired
  private Scheduler scheduler;

//    測試quartz 框架 定時任務
    public void sendMail() throws Exception {
        //設定開始時間為1分鐘後
        long startAtTime = System.currentTimeMillis() + 1000 * 60;
        //任務名稱
        String name = UUID.randomUUID().toString();
        //任務所屬分組
        String group = MyJob.class.getName();
        //建立任務
        JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity(name,group).build();
        //建立任務觸發器
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(name,group).startAt(new Date(startAtTime)).build();
        //將觸發器與任務繫結到排程器內
        scheduler.scheduleJob(jobDetail, trigger);
    }
}

還是像在單機下玩quartz一樣,需要傳入兩個物件(一個JobDetail,一個Trigger)任務詳情和觸發器。不懂的翻上文有做詳細介紹。好了 此時我們啟動專案,就可以看到控制檯列印,並且資料庫裡quar_等表也自動填入了定時任務的資訊。

我們大概只是完成了quartz的持久化,上文我們說過,quartz的亮點主要再對定時任務的可控性,那麼如果需要再後臺管理頁面上完成 增刪改查 定時任務。我推薦一個部落格給大家,寫的很好http://blog.csdn.net/u012907049/article/details/73801122

也謝謝這位作者。

最後謝謝大家,這篇文章挺長了。

相關推薦

spring boot2 整合定時任務Scheduled || Quartz持久化

在進入正文前,我想把所有java可以實現的定時任務介紹一下,其實這個也是底層實現思路。 本教程大概目錄: 1. 執行緒等待實現定時任務 2. 用Timer實現定時任務 3. 用ScheduledExecutorService實現定時任務 4.

spring boot2 整合Mybatis 特別完整!

one OS solver mapper ant gin enabled selectall pom 大概介紹下流程: 借助idea實現mybatis逆向工程 用xml配置實現整合 用cmd命令行實現mybatis逆向工程 用mapping.xml配置實現數據交互

spring-boot2-整合Mybatis-特別完整!

整合Mybatis分為兩種模式,一種是xml配置,一種是註解。(類似JPA) 我在這裡重點放在xml配置上,因為如果想用註解的話,建議直接用jpa代替,因為Jpa有更成熟的CRUD介面更方便開發。我在後文中也會把註解方式說清楚。 大概介紹下流程:

spring boot2 整合JPA特別完整!

JPA全稱Java Persistence API.JPA通過JDK 5.0註解或XML描述物件-關係表的對映關係,並將執行期的實體物件持久化到資料庫中。 JPA 的目標之一是制定一個可以由很多供應商實現的API,並且開發人員可以編碼來實現該AP

Spring ActiveMQ 整合: JMS 事務管理

1.為什麼要用事務?        訊息事務是在生產者producer到broker或broker到consumer過程中同一個session中發生的,保證幾條訊息在傳送過程中的原子性。      

Quartz學習總結2——定時任務框架Quartz詳解

實現每隔1秒列印一個Hello World1.建立Maven專案,新增依賴:<dependency>      <groupId>org.quartz-scheduler</groupId>      <artifactId>quartz</artifac

Spring Boot參考教程定時任務

blog esc ref tps targe 技術分享 lin ring tee 8. 定時任務 關於定時任務,考慮到應用的集群部署,一般會使用分布式的定時任務,後期章節會講述, 本章只演示Spring Boot提供的定時任務使用方式。 加入註解@EnableSc

spring-boot定時任務

在我們的專案開發過程中,經常需要定時任務來幫助我們來做一些內容,springboot預設已經幫我們實行了,只需要新增相應的註解就可以實現 1、pom包配置 pom包裡面只需要引入springboot starter包即可 <dependencies> <depe

Spring Boot 入門微服務之 Config Server 統一配置中心

bootstra pan pat 默認 star default client efault localhost 一、目錄結構 二、pom文件 <!-- 配置服務依賴 --> <dependency> &l

activiti自己定義流程之整合整合自己定義表單部署流程定義

borde row ont 創建 source als dst art select 綜合前幾篇博文內容。我想在整合這一部分中應該會有非常多模塊會跳過不講,就如自己定義表單的表單列表那一塊,由於這些模塊在整合的過程中都差點兒沒有什麽修改,再多講也是反復無用功。

Spring Boot學習

自動配置 pat xml配置 XML 入口 spa ges auto classpath @SpringBootApplication 每一個Spring Boot項目都有一個名為*Application的入口類,入口類中有個main方法,在main方法中使用: Sprin

Spring Boot入門——使用模板FreeMaker

junit boot.s char pack utf put 常見 節點 簡單的 這周主要學習怎麽在Spring Boot中使用模板引擎FreeMaker,主要從以下幾方面進行學習。 (1) freemarker介紹: FreeMarker是一款模板引擎: 即

Python學習記錄——Ubuntu計劃任務、grep、正則表達式

family count style 小時 ash 所有 當前 出現 spa 一.crontab用於計劃任務: 1.參數 (1)-u user:用來設定某個用戶的crontab服務 (2)-e:編輯某個用戶的crontab文件內容。如果不指定用戶,則表示編輯當前用戶的cro

Spring 使用介紹—— SpEL

true 定義變量 cati con jdb 多個 username pre prop 一、SpEL介紹 Spring表達式語言全稱為“Spring Expression Language”,縮寫為“SpEL”,可在運行時構建復雜表達式 使用步驟: 1)創建解析器:Expr

Spring學習筆記

array contain ets loader html 新的 -c spring學習 llb 本教程對應視頻課程:http://edu.51cto.com/course/14731.html 1、自動裝配 1.1、Spring標簽 Autowired標簽的作用 1、通過

spring cloud: Hystrix:feign類似於hystrix的斷容器功能

分享 use implement ack all cli req feign ret spring cloud: Hystrix(四):feign使用hystrix @FeignClient支持回退的概念:fallback方法,這裏有點類似於:@HystrixCommand

Spring原始碼解析——元件註冊4

  /** * 給容器中註冊元件; * 1)、包掃描+元件標註註解(@Controller/@Service/@Repository/@Component)[自己寫的類] * 2)、@Bean[匯入的第三方包裡面的元件] * 3)、@Import[快速給容器中匯入一個

自動裝配的幾種方式——Spring IOC/DI

本章主要講解自動裝配的幾種方式,接上一章依賴注入的方式以及裝配屬性: https://blog.csdn.net/qq_34598667/article/details/83308071 自動裝配之自動裝配的幾種方式 Spring 容器可以在不使用< construc

Spring啟動流程之Bean初始化前後的一些操作

【Spring原始碼分析】非懶載入的單例Bean初始化前後的一些操作   再看AbstractApplicationContext的refresh方法中的細節: Spring預設載入的兩個Bean,systemProperties和systemEnvironment,

spring+mybatis整合

一、applicationContext.xml配置 <!-- 設定掃描類 --><context:component-scan base-package="com.xxx.xxx"></context:component-scan> <bean id="data