国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

任務(wù)調(diào)度框架 Quartz 用法指南「超詳細(xì)」

共 9611字,需瀏覽 20分鐘

 ·

2022-05-28 07:01



大家好,我是胖虎!

今天早上,見(jiàn)交流群的小伙伴兒正在熱火朝天的討論著各種實(shí)現(xiàn)自定義定時(shí)任務(wù)的方案,從Quartz到Xxl-job,再到Elastic-job,能聊的都聊了一圈兒;剛剛好手頭有一份關(guān)于 Quartz 的保姆級(jí)教程,在這里分享給大家;

1前言

項(xiàng)目中遇到一個(gè),需要 客戶自定任務(wù)啟動(dòng)時(shí)間 的需求。原來(lái)一直都是在項(xiàng)目里硬編碼一些定時(shí)器,所以沒(méi)有學(xué)習(xí)過(guò)。

很多開(kāi)源的項(xiàng)目管理框架都已經(jīng)做了 Quartz 的集成。我們居然連這么常用得東西居然沒(méi)有做成模塊化,實(shí)在是不應(yīng)該。

Quartz是OpenSymphony開(kāi)源組織在Job scheduling領(lǐng)域又一個(gè)開(kāi)源項(xiàng)目,完全由Java開(kāi)發(fā),可以用來(lái)執(zhí)行定時(shí)任務(wù),類似于java.util.Timer。但是相較于Timer, Quartz增加了很多功能:

  • 持久性作業(yè) - 就是保持調(diào)度定時(shí)的狀態(tài);
  • 作業(yè)管理 - 對(duì)調(diào)度作業(yè)進(jìn)行有效的管理;

官方文檔:

  • http://www.quartz-scheduler.org/documentation/
  • http://www.quartz-scheduler.org/api/2.3.0/index.html

2基礎(chǔ)使用

Quartz 的核心類有以下三部分:

  • 任務(wù) Job : 需要實(shí)現(xiàn)的任務(wù)類,實(shí)現(xiàn) execute() 方法,執(zhí)行后完成任務(wù)。
  • 觸發(fā)器 Trigger : 包括 SimpleTriggerCronTrigger。
  • 調(diào)度器 Scheduler : 任務(wù)調(diào)度器,負(fù)責(zé)基于 Trigger觸發(fā)器,來(lái)執(zhí)行 Job任務(wù)。

主要關(guān)系如下:

3Demo

按照官網(wǎng)的 Demo,搭建一個(gè)純 maven 項(xiàng)目,添加依賴:


<dependency>
????<groupId>org.quartz-schedulergroupId>
????<artifactId>quartzartifactId>
????<version>2.3.0version>
dependency>

<dependency>
????<groupId>org.quartz-schedulergroupId>
????<artifactId>quartz-jobsartifactId>
????<version>2.3.0version>
dependency>

新建一個(gè)任務(wù),實(shí)現(xiàn)了 org.quartz.Job 接口:

public?class?MyJob?implements?Job?{
????@Override
????public?void?execute(JobExecutionContext?context)?throws?JobExecutionException?{
????????System.out.println("任務(wù)被執(zhí)行了。。。");
????}
}

main 方法,創(chuàng)建調(diào)度器、jobDetail 實(shí)例、trigger 實(shí)例、執(zhí)行:

public?static?void?main(String[]?args)?throws?Exception?{
????//?1.創(chuàng)建調(diào)度器?Scheduler
????SchedulerFactory?factory?=?new?StdSchedulerFactory();
????Scheduler?scheduler?=?factory.getScheduler();

????//?2.創(chuàng)建JobDetail實(shí)例,并與MyJob類綁定(Job執(zhí)行內(nèi)容)
????JobDetail?job?=?JobBuilder.newJob(MyJob.class)
????????.withIdentity("job1",?"group1")
????????.build()
;

????//?3.構(gòu)建Trigger實(shí)例,每隔30s執(zhí)行一次
????Trigger?trigger?=?TriggerBuilder.newTrigger()
????????.withIdentity("trigger1",?"group1")
????????.startNow()
????????.withSchedule(simpleSchedule()
??????????????????????.withIntervalInSeconds(30)
??????????????????????.repeatForever())
????????.build();

????//?4.執(zhí)行,開(kāi)啟調(diào)度器
????scheduler.scheduleJob(job,?trigger);
????System.out.println(System.currentTimeMillis());
????scheduler.start();

????//主線程睡眠1分鐘,然后關(guān)閉調(diào)度器
????TimeUnit.MINUTES.sleep(1);
????scheduler.shutdown();
????System.out.println(System.currentTimeMillis());
}

日志打印情況:

4JobDetail

JobDetail 的作用是綁定 Job,是一個(gè)任務(wù)實(shí)例,它為 Job 添加了許多擴(kuò)展參數(shù)。

每次Scheduler調(diào)度執(zhí)行一個(gè)Job的時(shí)候,首先會(huì)拿到對(duì)應(yīng)的Job,然后創(chuàng)建該Job實(shí)例,再去執(zhí)行Job中的execute()的內(nèi)容,任務(wù)執(zhí)行結(jié)束后,關(guān)聯(lián)的Job對(duì)象實(shí)例會(huì)被釋放,且會(huì)被JVM GC清除。

為什么設(shè)計(jì)成JobDetail + Job,不直接使用Job?

JobDetail 定義的是任務(wù)數(shù)據(jù),而真正的執(zhí)行邏輯是在Job中。

這是因?yàn)槿蝿?wù)是有可能并發(fā)執(zhí)行,如果Scheduler直接使用Job,就會(huì)存在對(duì)同一個(gè)Job實(shí)例并發(fā)訪問(wèn)的問(wèn)題。

JobDetail & Job 方式,Sheduler每次執(zhí)行,都會(huì)根據(jù)JobDetail創(chuàng)建一個(gè)新的Job實(shí)例,這樣就可以 規(guī)避并發(fā)訪問(wèn) 的問(wèn)題。

5JobExecutionContext

  • 當(dāng) Scheduler 調(diào)用一個(gè) job,就會(huì)將 JobExecutionContext 傳遞給 Job 的 execute() 方法;
  • Job 能通過(guò) JobExecutionContext 對(duì)象訪問(wèn)到 Quartz 運(yùn)行時(shí)候的環(huán)境以及 Job 本身的明細(xì)數(shù)據(jù)。

任務(wù)實(shí)現(xiàn)的 execute() 方法,可以通過(guò) context 參數(shù)獲取。

public?interface?Job?{
????void?execute(JobExecutionContext?context)
????????throws?JobExecutionException
;
}

Builder 建造過(guò)程中,可以使用如下方法:

usingJobData("tiggerDataMap",?"測(cè)試傳參")

execute 方法中獲?。?/p>

context.getTrigger().getJobDataMap().get("tiggerDataMap");
context.getJobDetail().getJobDataMap().get("tiggerDataMap");

6Job 狀態(tài)參數(shù)

有狀態(tài)的 job 可以理解為多次 job調(diào)用期間可以持有一些狀態(tài)信息,這些狀態(tài)信息存儲(chǔ)在 JobDataMap 中。

而默認(rèn)的無(wú)狀態(tài) job,每次調(diào)用時(shí)都會(huì)創(chuàng)建一個(gè)新的 JobDataMap。

示例如下:

//多次調(diào)用?Job?的時(shí)候,將參數(shù)保留在?JobDataMap
@PersistJobDataAfterExecution
public?class?JobStatus?implements?Job?{
????@Override
????public?void?execute(JobExecutionContext?context)?throws?JobExecutionException?{
????????long?count?=?(long)?context.getJobDetail().getJobDataMap().get("count");
????????System.out.println("當(dāng)前執(zhí)行,第"?+?count?+?"次");
????????context.getJobDetail().getJobDataMap().put("count",?++count);
????}
}
JobDetail?job?=?JobBuilder.newJob(JobStatus.class)
????????????????.withIdentity("statusJob",?"group1")
????????????????.usingJobData("count",?1L)
????????????????.build()
;

輸出結(jié)果:

當(dāng)前執(zhí)行,第1
[main]?INFO?org.quartz.core.QuartzScheduler?-?Scheduler?DefaultQuartzScheduler_$_NON_CLUSTERED?started.
當(dāng)前執(zhí)行,第2
當(dāng)前執(zhí)行,第3

7Trigger

定時(shí)啟動(dòng)/關(guān)閉

Trigger 可以設(shè)置任務(wù)的開(kāi)始結(jié)束時(shí)間, Scheduler 會(huì)根據(jù)參數(shù)進(jìn)行觸發(fā)。

Calendar?instance?=?Calendar.getInstance();
Date?startTime?=?instance.getTime();
instance.add(Calendar.MINUTE,?1);
Date?endTime?=?instance.getTime();

//?3.構(gòu)建Trigger實(shí)例
Trigger?trigger?=?TriggerBuilder.newTrigger()
????.withIdentity("trigger1",?"group1")
????//?開(kāi)始時(shí)間
????.startAt(startTime)
????//?結(jié)束時(shí)間
????.endAt(endTime)
????.build();

在 job 中也能拿到對(duì)應(yīng)的時(shí)間,并進(jìn)行業(yè)務(wù)判斷

public?void?execute(JobExecutionContext?context)?throws?JobExecutionException?{
????System.out.println("任務(wù)執(zhí)行。。。");
????System.out.println(context.getTrigger().getStartTime());
????System.out.println(context.getTrigger().getEndTime());
}

運(yùn)行結(jié)果:

[main]?INFO?org.quartz.impl.StdSchedulerFactory?-?Quartz?scheduler?version:?2.3.0
1633149326723
任務(wù)執(zhí)行。。。
Sat?Oct?02?12:35:26?CST?2021
Sat?Oct?02?12:36:26?CST?2021
[main]?INFO?org.quartz.core.QuartzScheduler?-?Scheduler?DefaultQuartzScheduler_$_NON_CLUSTERED?started.

8SimpleTrigger

這是比較簡(jiǎn)單的一類觸發(fā)器,用它能實(shí)現(xiàn)很多基礎(chǔ)的應(yīng)用。使用它的主要場(chǎng)景包括:

  • 在指定時(shí)間段內(nèi),執(zhí)行一次任務(wù)

    最基礎(chǔ)的 Trigger 不設(shè)置循環(huán),設(shè)置開(kāi)始時(shí)間。

  • 在指定時(shí)間段內(nèi),循環(huán)執(zhí)行任務(wù)

    在 1 基礎(chǔ)上加上循環(huán)間隔??梢灾付?永遠(yuǎn)循環(huán)、運(yùn)行指定次數(shù)

    TriggerBuilder.newTrigger()
    ????.withSchedule(SimpleScheduleBuilder
    ??????????????????.simpleSchedule()
    ??????????????????.withIntervalInSeconds(30)
    ??????????????????.repeatForever())

    withRepeatCount(count) 是重復(fù)次數(shù),實(shí)際運(yùn)行次數(shù)為 count+1

    TriggerBuilder.newTrigger()
    ????.withSchedule(SimpleScheduleBuilder
    ??????????????????.simpleSchedule()
    ??????????????????.withIntervalInSeconds(30)
    ??????????????????.withRepeatCount(5))
  • 立即開(kāi)始,指定時(shí)間結(jié)束

    這個(gè),略。

9CronTrigger

CronTrigger 是基于日歷的任務(wù)調(diào)度器,在實(shí)際應(yīng)用中更加常用。

雖然很常用,但是知識(shí)點(diǎn)都一樣,只是可以通過(guò)表達(dá)式來(lái)設(shè)置時(shí)間而已。

使用方式就是綁定調(diào)度器時(shí)換一下:

TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("*?*?*?*?*??"))

Cron 表達(dá)式這里不介紹,貼個(gè)圖跳過(guò)

順便推薦一個(gè)非常好用的Cron 表達(dá)式在線生成,反解析的工具:www.matools.com/cron 非常好用,點(diǎn)幾下,就能得到自己想要的cron表達(dá)式;

10SpringBoot 整合

下面集成應(yīng)用截圖來(lái)自 Ruoyi 框架:

從上面的截圖中,可以看到這個(gè)定時(shí)任務(wù)模塊實(shí)現(xiàn)了:

  • cron表達(dá)式定時(shí)執(zhí)行
  • 并發(fā)執(zhí)行
  • 錯(cuò)誤策略
  • 啟動(dòng)執(zhí)行、暫停執(zhí)行

如果再加上:設(shè)置啟動(dòng)時(shí)間、停止時(shí)間 就更好了。不過(guò)啟停時(shí)間只是調(diào)用兩個(gè)方法而已,也就不寫(xiě)了。

這一部分就主要是看 RuoYi 框架 代碼,然后加一點(diǎn)我需要用的功能。

前端部分就不寫(xiě)了,全部用 swagger 代替,一些基礎(chǔ)字段也刪除了,僅復(fù)制主體功能。

已完成代碼示例:

https://gitee.com/qianwei4712/code-of-shiva/tree/master/quartz

11環(huán)境準(zhǔn)備

從 springboot 2.4.10 開(kāi)始,添加 quartz 的 maven 依賴:


<dependency>
????<groupId>org.springframework.bootgroupId>
????<artifactId>spring-boot-starter-quartzartifactId>
dependency>

application 配置文件:

#?開(kāi)發(fā)環(huán)境配置
server:
??#?服務(wù)器的HTTP端口
??port:?80
??servlet:
????#?應(yīng)用的訪問(wèn)路徑
????context-path:?/
??tomcat:
????#?tomcat的URI編碼
????uri-encoding:?UTF-8

spring:
??datasource:
????username:?root
????password:?root
????url:?jdbc:mysql://127.0.0.1:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=true
????driver-class-name:?com.mysql.cj.jdbc.Driver

????#?HikariPool?較佳配置
????hikari:
??????#?客戶端(即您)等待來(lái)自池的連接的最大毫秒數(shù)
??????connection-timeout:?60000
??????#?控制將測(cè)試連接的活動(dòng)性的最長(zhǎng)時(shí)間
??????validation-timeout:?3000
??????#?控制允許連接在池中保持空閑狀態(tài)的最長(zhǎng)時(shí)間
??????idle-timeout:?60000

??????login-timeout:?5
??????#?控制池中連接的最大生存期
??????max-lifetime:?60000
??????#?控制允許池達(dá)到的最大大小,包括空閑和使用中的連接
??????maximum-pool-size:?10
??????#?控制HikariCP嘗試在池中維護(hù)的最小空閑連接數(shù)
??????minimum-idle:?10
??????#?控制默認(rèn)情況下從池獲得的連接是否處于只讀模式
??????read-only:?false

Quartz 自帶有數(shù)據(jù)庫(kù)模式,腳本都是現(xiàn)成的:

下載這個(gè)腳本:

https://gitee.com/qianwei4712/code-of-shiva/blob/master/quartz/quartz.sql

保存任務(wù)的數(shù)據(jù)庫(kù)表:

CREATE?TABLE?`quartz_job`?(
??`job_id`?bigint(20)?NOT?NULL?AUTO_INCREMENT?COMMENT?'任務(wù)ID',
??`job_name`?varchar(64)?NOT?NULL?DEFAULT?''?COMMENT?'任務(wù)名稱',
??`job_group`?varchar(64)?NOT?NULL?DEFAULT?'DEFAULT'?COMMENT?'任務(wù)組名',
??`invoke_target`?varchar(500)?NOT?NULL?COMMENT?'調(diào)用目標(biāo)字符串',
??`cron_expression`?varchar(255)?DEFAULT?''?COMMENT?'cron執(zhí)行表達(dá)式',
??`misfire_policy`?varchar(20)?DEFAULT?'3'?COMMENT?'計(jì)劃執(zhí)行錯(cuò)誤策略(1立即執(zhí)行?2執(zhí)行一次?3放棄執(zhí)行)',
??`concurrent`?char(1)?DEFAULT?'1'?COMMENT?'是否并發(fā)執(zhí)行(0允許?1禁止)',
??`status`?char(1)?DEFAULT?'0'?COMMENT?'狀態(tài)(0正常?1暫停)',
??`remark`?varchar(500)?DEFAULT?''?COMMENT?'備注信息',
??PRIMARY?KEY?(`job_id`,`job_name`,`job_group`)
)?ENGINE=InnoDB?AUTO_INCREMENT=2?DEFAULT?CHARSET=utf8?COMMENT='定時(shí)任務(wù)調(diào)度表';

最后準(zhǔn)備一個(gè)任務(wù)方法:

@Slf4j
@Component("mysqlJob")
public?class?MysqlJob?{
????protected?final?Logger?logger?=?LoggerFactory.getLogger(this.getClass());
????public?void?execute(String?param)?{
????????logger.info("執(zhí)行 Mysql Job,當(dāng)前時(shí)間:{},任務(wù)參數(shù):{}",?LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd?HH:mm:ss")),?param);
????}
}

12核心代碼

ScheduleConfig 配置代碼類:

@Configuration
public?class?ScheduleConfig?{

????@Bean
????public?SchedulerFactoryBean?schedulerFactoryBean(DataSource?dataSource)?{
????????SchedulerFactoryBean?factory?=?new?SchedulerFactoryBean();
????????factory.setDataSource(dataSource);

????????//?quartz參數(shù)
????????Properties?prop?=?new?Properties();
????????prop.put("org.quartz.scheduler.instanceName",?"shivaScheduler");
????????prop.put("org.quartz.scheduler.instanceId",?"AUTO");
????????//?線程池配置
????????prop.put("org.quartz.threadPool.class",?"org.quartz.simpl.SimpleThreadPool");
????????prop.put("org.quartz.threadPool.threadCount",?"20");
????????prop.put("org.quartz.threadPool.threadPriority",?"5");
????????//?JobStore配置
????????prop.put("org.quartz.jobStore.class",?"org.quartz.impl.jdbcjobstore.JobStoreTX");
????????//?集群配置
????????prop.put("org.quartz.jobStore.isClustered",?"true");
????????prop.put("org.quartz.jobStore.clusterCheckinInterval",?"15000");
????????prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime",?"1");
????????prop.put("org.quartz.jobStore.txIsolationLevelSerializable",?"true");

????????//?sqlserver?啟用
????????//?prop.put("org.quartz.jobStore.selectWithLockSQL",?"SELECT?*?FROM?{0}LOCKS?UPDLOCK?WHERE?LOCK_NAME?=??");
????????prop.put("org.quartz.jobStore.misfireThreshold",?"12000");
????????prop.put("org.quartz.jobStore.tablePrefix",?"QRTZ_");
????????factory.setQuartzProperties(prop);

????????factory.setSchedulerName("shivaScheduler");
????????//?延時(shí)啟動(dòng)
????????factory.setStartupDelay(1);
????????factory.setApplicationContextSchedulerContextKey("applicationContextKey");
????????//?可選,QuartzScheduler
????????//?啟動(dòng)時(shí)更新己存在的Job,這樣就不用每次修改targetObject后刪除qrtz_job_details表對(duì)應(yīng)記錄了
????????factory.setOverwriteExistingJobs(true);
????????//?設(shè)置自動(dòng)啟動(dòng),默認(rèn)為true
????????factory.setAutoStartup(true);

????????return?factory;
????}
}

ScheduleUtils 調(diào)度工具類,這是本篇中最核心的代碼:

public?class?ScheduleUtils?{
????/**
?????*?得到quartz任務(wù)類
?????*
?????*?@param?job?執(zhí)行計(jì)劃
?????*?@return?具體執(zhí)行任務(wù)類
?????*/

????private?static?Class?getQuartzJobClass(QuartzJob?job)?{
????????boolean?isConcurrent?=?"0".equals(job.getConcurrent());
????????return?isConcurrent???QuartzJobExecution.class?:?QuartzDisallowConcurrentExecution.class;
????}

????/**
?????*?構(gòu)建任務(wù)觸發(fā)對(duì)象
?????*/

????public?static?TriggerKey?getTriggerKey(Long?jobId,?String?jobGroup)?{
????????return?TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME?+?jobId,?jobGroup);
????}

????/**
?????*?構(gòu)建任務(wù)鍵對(duì)象
?????*/

????public?static?JobKey?getJobKey(Long?jobId,?String?jobGroup)?{
????????return?JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME?+?jobId,?jobGroup);
????}

????/**
?????*?創(chuàng)建定時(shí)任務(wù)
?????*/

????public?static?void?createScheduleJob(Scheduler?scheduler,?QuartzJob?job)?throws?Exception?{
????????Class?jobClass?=?getQuartzJobClass(job);
????????//?構(gòu)建job信息
????????Long?jobId?=?job.getJobId();
????????String?jobGroup?=?job.getJobGroup();
????????JobDetail?jobDetail?=?JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId,?jobGroup)).build();

????????//?表達(dá)式調(diào)度構(gòu)建器
????????CronScheduleBuilder?cronScheduleBuilder?=?CronScheduleBuilder.cronSchedule(job.getCronExpression());
????????cronScheduleBuilder?=?handleCronScheduleMisfirePolicy(job,?cronScheduleBuilder);

????????//?按新的cronExpression表達(dá)式構(gòu)建一個(gè)新的trigger
????????CronTrigger?trigger?=?TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId,?jobGroup))
????????????????.withSchedule(cronScheduleBuilder).build();

????????//?放入?yún)?shù),運(yùn)行時(shí)的方法可以獲取
????????jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES,?job);

????????//?判斷是否存在
????????if?(scheduler.checkExists(getJobKey(jobId,?jobGroup)))?{
????????????//?防止創(chuàng)建時(shí)存在數(shù)據(jù)問(wèn)題?先移除,然后在執(zhí)行創(chuàng)建操作
????????????scheduler.deleteJob(getJobKey(jobId,?jobGroup));
????????}

????????scheduler.scheduleJob(jobDetail,?trigger);

????????//?暫停任務(wù)
????????if?(job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue()))?{
????????????scheduler.pauseJob(ScheduleUtils.getJobKey(jobId,?jobGroup));
????????}
????}

????/**
?????*?設(shè)置定時(shí)任務(wù)策略
?????*/

????public?static?CronScheduleBuilder?handleCronScheduleMisfirePolicy(QuartzJob?job,?CronScheduleBuilder?cb)
????????????throws?Exception?
{
????????switch?(job.getMisfirePolicy())?{
????????????case?ScheduleConstants.MISFIRE_DEFAULT:
????????????????return?cb;
????????????case?ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
????????????????return?cb.withMisfireHandlingInstructionIgnoreMisfires();
????????????case?ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
????????????????return?cb.withMisfireHandlingInstructionFireAndProceed();
????????????case?ScheduleConstants.MISFIRE_DO_NOTHING:
????????????????return?cb.withMisfireHandlingInstructionDoNothing();
????????????default:
????????????????throw?new?Exception("The?task?misfire?policy?'"?+?job.getMisfirePolicy()
????????????????????????+?"'?cannot?be?used?in?cron?schedule?tasks");
????????}
????}
}

這里可以看到,在完成任務(wù)與觸發(fā)器的關(guān)聯(lián)后,如果是暫停狀態(tài),會(huì)先讓調(diào)度器停止任務(wù)。

AbstractQuartzJob 抽象任務(wù):

public?abstract?class?AbstractQuartzJob?implements?Job?{
????private?static?final?Logger?log?=?LoggerFactory.getLogger(AbstractQuartzJob.class);

????/**
?????*?線程本地變量
?????*/

????private?static?ThreadLocal?threadLocal?=?new?ThreadLocal<>();

????@Override
????public?void?execute(JobExecutionContext?context)?throws?JobExecutionException?{
????????QuartzJob?job?=?new?QuartzJob();
????????BeanUtils.copyBeanProp(job,?context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
????????try?{
????????????before(context,?job);
????????????if?(job?!=?null)?{
????????????????doExecute(context,?job);
????????????}
????????????after(context,?job,?null);
????????}?catch?(Exception?e)?{
????????????log.error("任務(wù)執(zhí)行異常??-?:",?e);
????????????after(context,?job,?e);
????????}
????}

????/**
?????*?執(zhí)行前
?????*
?????*?@param?context?工作執(zhí)行上下文對(duì)象
?????*?@param?job?????系統(tǒng)計(jì)劃任務(wù)
?????*/

????protected?void?before(JobExecutionContext?context,?QuartzJob?job)?{
????????threadLocal.set(new?Date());
????}

????/**
?????*?執(zhí)行后
?????*
?????*?@param?context?工作執(zhí)行上下文對(duì)象
?????*?@param?sysJob??系統(tǒng)計(jì)劃任務(wù)
?????*/

????protected?void?after(JobExecutionContext?context,?QuartzJob?sysJob,?Exception?e)?{

????}

????/**
?????*?執(zhí)行方法,由子類重載
?????*
?????*?@param?context?工作執(zhí)行上下文對(duì)象
?????*?@param?job?????系統(tǒng)計(jì)劃任務(wù)
?????*?@throws?Exception?執(zhí)行過(guò)程中的異常
?????*/

????protected?abstract?void?doExecute(JobExecutionContext?context,?QuartzJob?job)?throws?Exception;
}

這個(gè)類將原本 execute 方法執(zhí)行的任務(wù),下放到了子類重載的 doExecute 方法中

同時(shí)準(zhǔn)備實(shí)現(xiàn),分了允許并發(fā)和不允許并發(fā),差別就是一個(gè)注解:

public?class?QuartzJobExecution?extends?AbstractQuartzJob?{
????@Override
????protected?void?doExecute(JobExecutionContext?context,?QuartzJob?job)?throws?Exception?{
????????JobInvokeUtil.invokeMethod(job);
????}
}
@DisallowConcurrentExecution
public?class?QuartzDisallowConcurrentExecution?extends?AbstractQuartzJob?{
????@Override
????protected?void?doExecute(JobExecutionContext?context,?QuartzJob?job)?throws?Exception?{
????????JobInvokeUtil.invokeMethod(job);
????}
}

最后由 JobInvokeUtil 通過(guò)反射,進(jìn)行實(shí)際的方法調(diào)用:

public?class?JobInvokeUtil?{
????/**
?????*?執(zhí)行方法
?????*
?????*?@param?job?系統(tǒng)任務(wù)
?????*/

????public?static?void?invokeMethod(QuartzJob?job)?throws?Exception?{
????????String?invokeTarget?=?job.getInvokeTarget();
????????String?beanName?=?getBeanName(invokeTarget);
????????String?methodName?=?getMethodName(invokeTarget);
????????List?methodParams?=?getMethodParams(invokeTarget);

????????if?(!isValidClassName(beanName))?{
????????????Object?bean?=?SpringUtils.getBean(beanName);
????????????invokeMethod(bean,?methodName,?methodParams);
????????}?else?{
????????????Object?bean?=?Class.forName(beanName).newInstance();
????????????invokeMethod(bean,?methodName,?methodParams);
????????}
????}

????/**
?????*?調(diào)用任務(wù)方法
?????*
?????*?@param?bean?????????目標(biāo)對(duì)象
?????*?@param?methodName???方法名稱
?????*?@param?methodParams?方法參數(shù)
?????*/

????private?static?void?invokeMethod(Object?bean,?String?methodName,?List?methodParams)
????????????throws?NoSuchMethodException,?SecurityException,?IllegalAccessException,?IllegalArgumentException,
????????????InvocationTargetException?
{
????????if?(StringUtils.isNotNull(methodParams)?&&?methodParams.size()?>?0)?{
????????????Method?method?=?bean.getClass().getDeclaredMethod(methodName,?getMethodParamsType(methodParams));
????????????method.invoke(bean,?getMethodParamsValue(methodParams));
????????}?else?{
????????????Method?method?=?bean.getClass().getDeclaredMethod(methodName);
????????????method.invoke(bean);
????????}
????}

????/**
?????*?校驗(yàn)是否為為class包名
?????*
?????*?@param?invokeTarget?名稱
?????*?@return?true是?false否
?????*/

????public?static?boolean?isValidClassName(String?invokeTarget)?{
????????return?StringUtils.countMatches(invokeTarget,?".")?>?1;
????}

????/**
?????*?獲取bean名稱
?????*
?????*?@param?invokeTarget?目標(biāo)字符串
?????*?@return?bean名稱
?????*/

????public?static?String?getBeanName(String?invokeTarget)?{
????????String?beanName?=?StringUtils.substringBefore(invokeTarget,?"(");
????????return?StringUtils.substringBeforeLast(beanName,?".");
????}

????/**
?????*?獲取bean方法
?????*
?????*?@param?invokeTarget?目標(biāo)字符串
?????*?@return?method方法
?????*/

????public?static?String?getMethodName(String?invokeTarget)?{
????????String?methodName?=?StringUtils.substringBefore(invokeTarget,?"(");
????????return?StringUtils.substringAfterLast(methodName,?".");
????}

????/**
?????*?獲取method方法參數(shù)相關(guān)列表
?????*
?????*?@param?invokeTarget?目標(biāo)字符串
?????*?@return?method方法相關(guān)參數(shù)列表
?????*/

????public?static?List?getMethodParams(String?invokeTarget)?{
????????String?methodStr?=?StringUtils.substringBetween(invokeTarget,?"(",?")");
????????if?(StringUtils.isEmpty(methodStr))?{
????????????return?null;
????????}
????????String[]?methodParams?=?methodStr.split(",");
????????List?classs?=?new?LinkedList<>();
????????for?(int?i?=?0;?i?????????????String?str?=?StringUtils.trimToEmpty(methodParams[i]);
????????????//?String字符串類型,包含'
????????????if?(StringUtils.contains(str,?"'"))?{
????????????????classs.add(new?Object[]{StringUtils.replace(str,?"'",?""),?String.class});
????????????}
????????????//?boolean布爾類型,等于true或者false
????????????else?if?(StringUtils.equals(str,?"true")?||?StringUtils.equalsIgnoreCase(str,?"false"))?{
????????????????classs.add(new?Object[]{Boolean.valueOf(str),?Boolean.class});
????????????}
????????????//?long長(zhǎng)整形,包含L
????????????else?if?(StringUtils.containsIgnoreCase(str,?"L"))?{
????????????????classs.add(new?Object[]{Long.valueOf(StringUtils.replaceIgnoreCase(str,?"L",?"")),?Long.class});
????????????}
????????????//?double浮點(diǎn)類型,包含D
????????????else?if?(StringUtils.containsIgnoreCase(str,?"D"))?{
????????????????classs.add(new?Object[]{Double.valueOf(StringUtils.replaceIgnoreCase(str,?"D",?"")),?Double.class});
????????????}
????????????//?其他類型歸類為整形
????????????else?{
????????????????classs.add(new?Object[]{Integer.valueOf(str),?Integer.class});
????????????}
????????}
????????return?classs;
????}

????/**
?????*?獲取參數(shù)類型
?????*
?????*?@param?methodParams?參數(shù)相關(guān)列表
?????*?@return?參數(shù)類型列表
?????*/

????public?static?Class[]?getMethodParamsType(List?methodParams)?{
????????Class[]?classs?=?new?Class[methodParams.size()];
????????int?index?=?0;
????????for?(Object[]?os?:?methodParams)?{
????????????classs[index]?=?(Class)?os[1];
????????????index++;
????????}
????????return?classs;
????}

????/**
?????*?獲取參數(shù)值
?????*
?????*?@param?methodParams?參數(shù)相關(guān)列表
?????*?@return?參數(shù)值列表
?????*/

????public?static?Object[]?getMethodParamsValue(List?methodParams)?{
????????Object[]?classs?=?new?Object[methodParams.size()];
????????int?index?=?0;
????????for?(Object[]?os?:?methodParams)?{
????????????classs[index]?=?(Object)?os[0];
????????????index++;
????????}
????????return?classs;
????}
}

啟動(dòng)程序后可以看到,調(diào)度器已經(jīng)啟動(dòng):

2021-10-06?16:26:05.162??INFO?10764?---?[shivaScheduler]]?o.s.s.quartz.SchedulerFactoryBean????????:?Starting?Quartz?Scheduler?now,?after?delay?of?1?seconds
2021-10-06?16:26:05.306??INFO?10764?---?[shivaScheduler]]?org.quartz.core.QuartzScheduler??????????:?Scheduler?shivaScheduler_$_DESKTOP-OKMJ1351633508761366?started.

13新增調(diào)度任務(wù)

添加任務(wù),使用如下 json 進(jìn)行請(qǐng)求:

{
??"concurrent":?"1",
??"cronExpression":?"0/10?*?*?*?*??",
??"invokeTarget":?"mysqlJob.execute('got?it!!!')",
??"jobGroup":?"mysqlGroup",
??"jobId":?9,
??"jobName":?"新增?mysqlJob?任務(wù)",
??"misfirePolicy":?"1",
??"remark":?"",
??"status":?"0"
}
@Override
@Transactional(rollbackFor?=?Exception.class)
public?int?insertJob(QuartzJob?job)?throws?Exception?
{
????//?先將任務(wù)設(shè)置為暫停狀態(tài)
????job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
????int?rows?=?quartzMapper.insert(job);
????if?(rows?>?0)?{
????????ScheduleUtils.createScheduleJob(scheduler,?job);
????}
????return?rows;
}

先將任務(wù)設(shè)置為暫停狀態(tài),數(shù)據(jù)庫(kù)插入成功后,在調(diào)度器創(chuàng)建任務(wù)。

再手動(dòng)啟動(dòng)任務(wù),根據(jù) ID 來(lái)啟動(dòng)任務(wù):

實(shí)現(xiàn)代碼:

@Override
????public?int?changeStatus(Long?jobId,?String?status)?throws?SchedulerException?{
????????int?rows?=?quartzMapper.changeStatus(jobId,?status);
????????if?(rows?==?0)?{
????????????return?rows;
????????}
????????//更新成功,需要改調(diào)度器內(nèi)任務(wù)的狀態(tài)
????????//拿到整個(gè)任務(wù)
????????QuartzJob?job?=?quartzMapper.selectJobById(jobId);
????????//根據(jù)狀態(tài)來(lái)啟動(dòng)或者關(guān)閉
????????if?(ScheduleConstants.Status.NORMAL.getValue().equals(status))?{
????????????rows?=?resumeJob(job);
????????}?else?if?(ScheduleConstants.Status.PAUSE.getValue().equals(status))?{
????????????rows?=?pauseJob(job);
????????}
????????return?rows;
????}
@Override
public?int?resumeJob(QuartzJob?job)?throws?SchedulerException?{
????Long?jobId?=?job.getJobId();
????String?jobGroup?=?job.getJobGroup();
????job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
????int?rows?=?quartzMapper.updateById(job);
????if?(rows?>?0)?{
????????scheduler.resumeJob(ScheduleUtils.getJobKey(jobId,?jobGroup));
????}
????return?rows;
}

暫停任務(wù)的代碼也相同。

調(diào)用啟動(dòng)后可以看到控制臺(tái)打印日志:

2021-10-06?20:36:30.018??INFO?8536?---?[eduler_Worker-3] cn.shiva.quartz.job.MysqlJob ????????????:?執(zhí)行 Mysql Job,當(dāng)前時(shí)間:2021-10-06?20:36:30,任務(wù)參數(shù):got it!!!
2021-10-06?20:36:40.016??INFO?8536?---?[eduler_Worker-4] cn.shiva.quartz.job.MysqlJob ????????????:?執(zhí)行 Mysql Job,當(dāng)前時(shí)間:2021-10-06?20:36:40,任務(wù)參數(shù):got it!!!
2021-10-06?20:36:50.017??INFO?8536?---?[eduler_Worker-5] cn.shiva.quartz.job.MysqlJob ????????????:?執(zhí)行 Mysql Job,當(dāng)前時(shí)間:2021-10-06?20:36:50,任務(wù)參數(shù):got it!!!

如果涉及到任務(wù)修改,需要在調(diào)度器先刪除原有任務(wù),重新創(chuàng)建調(diào)度任務(wù)。

啟動(dòng)初始化任務(wù)

這部分倒是比較簡(jiǎn)單,初始化的時(shí)候清空原有任務(wù),重新創(chuàng)建就好了:

/**
??*?項(xiàng)目啟動(dòng)時(shí),初始化定時(shí)器?主要是防止手動(dòng)修改數(shù)據(jù)庫(kù)導(dǎo)致未同步到定時(shí)任務(wù)處理(注:不能手動(dòng)修改數(shù)據(jù)庫(kù)ID和任務(wù)組名,否則會(huì)導(dǎo)致臟數(shù)據(jù))
??*/

@PostConstruct
public?void?init()?throws?Exception?{
????scheduler.clear();
????List?jobList?=?quartzMapper.selectJobAll();
????for?(QuartzJob?job?:?jobList)?{
????????ScheduleUtils.createScheduleJob(scheduler,?job);
????}
}

14其他說(shuō)明

并發(fā)執(zhí)行

上面有并發(fā)和非并發(fā)的區(qū)別,通過(guò) @DisallowConcurrentExecution 注解來(lái)實(shí)現(xiàn)阻止并發(fā)。

Quartz定時(shí)任務(wù)默認(rèn)都是并發(fā)執(zhí)行的,不會(huì)等待上一次任務(wù)執(zhí)行完畢,只要間隔時(shí)間到就會(huì)執(zhí)行, 如果定時(shí)任執(zhí)行太長(zhǎng),會(huì)長(zhǎng)時(shí)間占用資源,導(dǎo)致其它任務(wù)堵塞。

@DisallowConcurrentExecution 禁止并發(fā)執(zhí)行多個(gè)相同定義的JobDetail, 這個(gè)注解是加在Job類上的, 但意思并不是不能同時(shí)執(zhí)行多個(gè)Job, 而是不能并發(fā)執(zhí)行同一個(gè)Job Definition(由JobDetail定義), 但是可以同時(shí)執(zhí)行多個(gè)不同的JobDetail。

舉例說(shuō)明,我們有一個(gè)Job類,叫做SayHelloJob, 并在這個(gè)Job上加了這個(gè)注解, 然后在這個(gè)Job上定義了很多個(gè)JobDetail, 如sayHelloToJoeJobDetail, sayHelloToMikeJobDetail, 那么當(dāng)scheduler啟動(dòng)時(shí), 不會(huì)并發(fā)執(zhí)行多個(gè)sayHelloToJoeJobDetail或者sayHelloToMikeJobDetail, 但可以同時(shí)執(zhí)行sayHelloToJoeJobDetailsayHelloToMikeJobDetail

@PersistJobDataAfterExecution 同樣, 也是加在Job上。表示當(dāng)正常執(zhí)行完Job后, JobDataMap中的數(shù)據(jù)應(yīng)該被改動(dòng), 以被下一次調(diào)用時(shí)用。

當(dāng)使用 @PersistJobDataAfterExecution 注解時(shí), 為了避免并發(fā)時(shí), 存儲(chǔ)數(shù)據(jù)造成混亂, 強(qiáng)烈建議把 @DisallowConcurrentExecution 注解也加上。

測(cè)試代碼,設(shè)定的時(shí)間間隔為3秒,但job執(zhí)行時(shí)間是5秒,設(shè)置 @DisallowConcurrentExecution以 后程序會(huì)等任務(wù)執(zhí)行完畢以后再去執(zhí)行,否則會(huì)在3秒時(shí)再啟用新的線程執(zhí)行。

阻止特定時(shí)間運(yùn)行

仍然是通過(guò)調(diào)度器實(shí)現(xiàn)的:

//2014-8-15這一天不執(zhí)行任何任務(wù)
Calendar?c?=?new?GregorianCalendar(2014,?7,?15);
cal.setDayExcluded(c,?true);
scheduler.addCalendar("exclude",?cal,?false,?false);

//...中間省略
TriggerBuilder.newTrigger().modifiedByCalendar("exclude")....

來(lái)源:https://blog.csdn.net/m0_46144826


如有文章對(duì)你有幫助,

在看”和轉(zhuǎn)發(fā)是對(duì)我最大的支持!

推薦

點(diǎn)擊領(lǐng)?。?span style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">151個(gè)大廠面試講解!(圖片可上下滑動(dòng)?。??


瀏覽 45
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)
評(píng)論
圖片
表情
推薦
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 日本黄色片| 成人片无码| 怡春院av| AV天堂影视在线观看| 国产AV无码一区| 黄色视频A| 中文字幕在线视频免费观看| 尤物视频网| 2025最新国产精品每日更新| 超碰免费视| 日本精品黄色| 在线观看欧美日韩| 五月婷婷在线视频| 开心色色五月天| 一级内射片在线网站观看| 欧美午夜精品久久久久久3D| 国产激情网| 大秀91视频| 99国产高清| 天天操电影| 国产乱伦电影| 四季AV一区二区凹凸懂色桃花| 国产无码性爱| 中文字幕AV播放| 亚洲18禁| 午夜无码福利在线观看| 黄色一级免费电影| 午夜操一操| 日日夜夜天天综合| 色婷婷视频网站| 操中国老女人| 成人免费无码激情AV片| aaa片| 欧美a视频| 一本色道久久88综合无码| 天天综合在线观看| 91做爱视频| 欧美日韩AV| 久久国产一区二区三区| 老熟女乱伦| 自拍视频在线| 欧美在线大香蕉| 亚洲高清在线视频| 波多野结衣视频无码| 黄片免费播放| 在线成人一区二区| 国产成人综合电影| 日本免费中文字幕| 婷婷六区| 国产超碰| 大香蕉电影网| 黄片高清无码在线观看| 亚洲天堂免费观看| 无码成人毛片| 国产91免费| 天天色色综合| 亚洲欧洲在线播放| 无码专区在线观看| 国产AV高清| 九九五月天| 久久久久无码精品亚洲日韩| 亚洲免费在线视频| 亚洲无码高清在线视频| 九色91| 操女人的网站| 无码精品视频在线观看| 超碰自拍99| 国产色情视频在线观看| 香蕉成人电影| 日韩精品网址| 依人成人| 凸凹翔田千里无码| 成人无码区免费A片| 牛牛精品一区二区AV| 日韩婬乱片A片AAA真人视频| 青草伊人网| 亚洲A片一区二区三区电影网 | 色三区| 乱轮少妇| 免费中文字幕av| 日韩无码高清视频| 成人毛片在线视频| 日韩中文字幕视频| 午夜黄色大片| 亚洲AV日韩AV永久无码网站| 你懂的视频在线播放| 西西444WWW大胆无| 大鸡吧草逼| 久久男人网| 成人黄网站在线观看| 亚洲一区二区三| 九九成人免费视频| 中文在线字幕电视剧免费平台| 久久视频这里有精品| 麻豆A∨在线| 性爱av在线观看| 99热99精品| 精品国产久久久久| 91免费小视频| 天天干免费视频| 久久免费观看视频| 婷婷午夜福利| 亚洲免费清高| 三级国产AV| 国产精品AV片| 在线黄色小视频| 日本天堂网在线观看| 无码黄色片| 蜜桃AV在线观看| 在线观看黄色视频网站| 国产欧美日韩视频| 欧美日韩有码视频网址大全 | 在线观看中文字幕视频| 亚洲日韩中文无码| 一区无码高清| 在线人妻| 艳妇乳肉豪妇荡乳AV无码福利| 亚洲欧美手机在线| 秋霞午夜| 成人黄网站免费视频| 中文字幕无码视频| 日批网站视频| 黄色片在线视频| 一级黄色电影网站| 成人精品一区日本无码网站suv| 丁香婷婷五月| 人人干干| 91欧美精品成人AAA片| 国产综合激情| 国产精品视频无码| 成人黄片在线免费观看| 亚洲免费在线播放| 日韩夜夜操| 国产免费操逼| 日韩一区无码| 一级a免一级a做免费线看内裤的注意事项 | 国产日韩欧美一区| 亚洲黑人av| 国产三级片网站| 亚洲AV无码久久精品色无码蜜桃| AV国产精品| 一级黄色大片| 亚洲日韩激情| 国产成人精品一区二区三区视频| 国产又黄又大又粗| 亚洲精品在线视频| 97人人精品| 五月激情久久| 欧美天堂成人三级| 青青草激情视频| 亚洲欧美日韩动漫| www.777熟女人妻| 国产深夜福利| 欧美日韩在线视频免费观看| 国产毛片18水真多18精品| 婷婷综合视频| 亚洲无码人妻| 日韩a√| 欧美久久电影| 在线观看黄色片| 中文日韩在线| 伊人综合影院| 一本大道久久久久| 精品网站999www| 97人妻一区二区三区| 女人18片毛片60分钟翻译| 亚洲无码影视| 国产一二三四区| 麻豆md0049免费| 国产精品视频在线播放| 免费的黄色A片| 亚洲成人三区| 欧美午夜精品成人片在线播放| 伊人免费成人视频| 91麻豆国产在线| 操噜噜噜噜噜插| 岛国无码在线| 老太色HD色老太HD| 在线国产福利| 欧美韩日一区二区| 一级性生活视频| 俺来也俺去也| 人人摸人人射| 京东一热本色道久久爱| www.199麻豆在线观看网站| 一级A片黃色A片| 黄色操逼网站?| 先锋影音av资源网| 国产乱妇乱子伦视频免费观看让女人| 99色99| 亚洲三级黄片| 久久精品国产AV一区二区三区| 99在线免费视频| 嫩草亚洲小泬久久夂| 无码人妻中文字幕| 欧美成人怡红院| 1区2区视频| 三须三级久久三级久久18| 水果派解说A∨无码区| 人人射| 久久久久免费视频| 美日韩中文字幕| 欧美精品日韩| 精品无码一区二区Av蜜桃| A片黄色视频| 亚洲色男人天堂| 狠狠干五月| 大香蕉久久久| 中文字幕av久久久久久欧洲尺码 | a√天堂中文在线8| 就要操逼| 天堂中文在线播放| 精品尤物在线| 粉嫩99精品99久久久久久特污兔 | 婷婷综合视频| 国产黄色网页| 伊人久久艹| 狠狠干2021| 亚洲人妻无码一区| 加勒比黑人和翔田千里在线播放| 麻豆免费视频| 日韩欧美中文在线| 色欲一区| 7777AV| 丁香五月婷婷在线| 午夜福利影片| 日韩在线视频中文字幕| v天堂| 国产香蕉91| 西西WWW888大胆无码| 久久久久久少妇| 一本久道视频一本久道| 粉嫩AV在线| 亚洲精品系列| 亚洲AV资源在线| 婷婷好色五月天| 婷婷成人小说| 操逼网视频| 无码人妻精品一区二区50| 午夜老司机福利| 91精品国产成人www| 水果派成人播放无码| 日本人妻中出| 丁香六月激情| 亚洲欧美性爱| 人妻无码中文字幕免费视频蜜桃| 青春草视频在线观看| 日本a片| 欧美成人网站在线观看| 亚洲欧美视频在线| 免费无码婬片AAAA片直播| 五月香婷婷| 欧美日韩高清一区二区三区| 91小视频在线| 久久久久无码精品国产91福利 | 一级爱爱免费视频| 中文字幕乱妇无码Av在线| 欧美一区二区三区视频| A片网| 成人做爰免费网站2023| 败火老熟女ThePorn视频| 精品一区二区三区av| 国产成人精品毛片| 一本久道视频一本久道| 91爱爱爱爱| 色图15p| AA丁香综合激情| 日韩香蕉网| 国产成人片在线观看| 2024AV在线| 激情国产精品| 色综合999| 国产aa片| 亚洲AV无码久久精品色无码蜜桃| 亚洲免费观看高清完整版在va线观 | 日本不卡一区| 久久久久久久久久国产精品免费观看-百度 | 精品久久一区二区三区四区| 日韩无码影视| www.A片| 影音先锋AV啪啪资源| 天堂在线无码| 在线观看黄片视频| 偷拍99| 伊人久久影院| 成人国产精品秘在线看| 欧美一级片免费看| 国产91在线看| 12——13女人毛片毛片| 亚洲人妻无码一区| 果冻传媒一区二区三区| 大香蕉av在线| av人人| 波多野结衣av一区| 青青草大香蕉伊人| 视频在线观看一区| 一级黄色视频网站| 日韩强操逼网| 91探花足浴店按摩店| 精品人妻系列| 美女一级A片| 91精品国产乱码香蕉黄瓜草莓| 免费在线观看视频a| 日皮在线观看| 九九亚洲| 77777免费观看电视剧推荐爱的教育| 天堂网址激情网址| 欧美精品三区| 免费无码一级A片大黄在线观看| 成人国产AV精| 久久ww| 91麻豆天美传媒在线| 俺也要操| 日韩性做爰免费A片AA片| 91久久综合亚洲鲁鲁五月天| 小日本91在线观看| 无码欧美精品一区二区| 东方av在线免费观看| 操婷婷| 无码人妻一区二区三区四区老鸭窝| 影音先锋AV成人| 国产字幕| 99视频久久| 又紧又嫩又爽无遮挡免费| 99色视频| 日本黄色片| 久久免费9| 精品无码一区二区三区的天堂| 成人区精品一区二区婷婷| 亚洲成人网站在线| 亚洲AV成人无码精品直播在线| 中文字幕第六页| 羞羞视频com.入口| 亚洲中文字幕一区| 日日夜夜草| 熟女在线视频| 精品视频| 国产av一二三区| 亚洲天堂婷婷| 青娱乐毛片| 91大神免费观看| 亚洲天堂视频网站| 三根一起进菊眼| 日韩操B| 国产丝袜AV| 欧美+日韩+国产+成人+在线| 欧美人妻激情| 国产成人精品三级麻豆| 欧美精品无码一区二区| 日韩骚货| 日本色色视频| 91国产视频网站| 一区二区入口| 91久久欧美极品XXXXⅩ| 夜夜操狠狠操| 五月天激情导航| 欧美视频一区二区三区| www.91在线看| 日韩欧美精品在线观看| 色色欧美色色| 国产精品久久免费| 特级西西人体WWWww| 日本中文字幕乱伦| 国产色视频一区二区三区QQ号| 久草社区| 亚洲瑟瑟| 自拍偷拍影音先锋| sesese999| 青娱乐国产精品一区二区| 荫蒂添的高潮免费视频| 国产主播福利| 亚洲日韩一区二区三区| A一级黄色片| 中文字幕免费| 一区二区成人视频| 波多野结衣无码视频在线观看| 午夜成人无码视频| 毛片小说| 国产免费激情视频| wwwsesese| 高清一区二区| 综合色色婷婷| 亚洲午夜福利在线观看| 亚洲黄色在线播放| 大香焦久久| 亚洲色成人中文字幕在线| 青娱乐国产在线视频| 国产成人片色情AAAA片| 刘玥一区二区三区| 成人av黄色三级片在线观看| 国內精品久久久久久久| 毛片网站在线观看| 亚洲AV成人电影| 人妻AV一区| 好色综合| 996精品视频| 学生妹做爱视频| 日韩午夜无码| 欧美精品网站| 9999re| 在线观看亚洲天堂| 超碰人人人人人人人人| 亚洲有码在线观看| 肏屄在线观看| 操毛| 黄av在线| 日韩日逼| 欧美性爱69| 国产无套进入免费| 亚洲欧美卡通| 最近中文字幕在线视频| 国产无遮挡又黄又爽| 日韩操大屌| 丁香五月天在线| 人人澡人人爽欧一区| 色五月婷婷婷| 日韩中文在线观看| 日本视频一区二区| 春色激情| 无码无卡| 久久婷视频| www男人天堂| 欧美黄色免费| 极品人妻疯狂3p超刺激| 男人午夜网站| 成人网址| 2019国产精品| 日产久久久| 男女AV在线| 国产女人18水真多18精品 | 91看片看婬黄大片| 五月亚洲六月婷婷| 人人草在线视频| 国产一级婬乱片免费| 黄色片免费| 77久久| 麻豆毛片| 成人av无码| 国产高潮又爽又无遮挡又免费| jizz麻豆| www.蜜桃av| 日韩中文字幕视频| 欧美日韩国产成人综合| 免费看性蜜桃| 黄色视频网站在线免费观看| 国产女人18水真多18精品| 亚洲视频第一页| 中文不卡在线| 91要爱爱| 国产精品无码永久免费不卡| 色视频国产| 成人视频91| 色婷婷亚洲综合| 免费国产成人看片在线| 一本到在线观看午夜剧场| 亚洲欧美日韩综合| 亲子伦一区二区三区观看方式| 午夜亚洲国产一区视频网站| 亚洲精品在线看| 一区二区三区无码精品| 日本成人视频在线免费播放| 国产17c精品视频一二三区| 红桃91人妻爽人妻爽| 国产欧美综合视频一区二区在线 | 大鸡巴久久久| 久久婷婷婬片A片AAA| 色av影音先锋无吗一区| 亚洲无码视频一区| 91人妻人人澡人人爽人人爽 | 亚洲男人的天堂AV| 大香蕉在线视频观看| 亚洲AV无码专区一级婬片毛片 | 蜜芽成人精品久久久视频| 午夜操p| 日日夜夜天天| 国产精品秘久久久久久一两个一起| 国产免费黄色视频网站| 黄色电影免费在线观看| 日韩一级无码特黄AAA片| A片在线免费| 人人妻人人澡人人爽久久| 黄色成人网站在线播放| 亚洲中文偷拍| 国产精品无码激情视频| 日本无码中文字幕| 亚洲午夜福利在线| a片免费观看视频| 国产精品秘精东影业| 足浴小少妇-88AX| 黄色直播在线观看| 日本爱爱免费播放视频| 国产激情视频| 俺来俺去| 闺蜜av| 51妺嘿嘿午夜福利视频| 亚洲视频三区| 天天操天天操免费视频| 国产美女精品| 亚洲激情四射| 大香蕉9999| 久久婷婷五月| 四虎性爱| 无码99| 精品无码一区二区三区蜜桃李宗瑞| 婷婷精品秘进入| www.zaixianshipin| 天天日天天操天天干| 中文字幕在线网址| 欧美日韩久久久| 午夜视频免费在线观看| 激情AV在线观看| 精品免费国产一区二区三区四区的使用方法 | 亚洲高清无码一区二区三区| 麻豆乱伦视频| 人人天天爽| av一区在线观看| 操逼首页123| 东京热网站在线观看| 午夜无码鲁丝片午夜精品一区二区| 欧美成人毛片| 日本久久网| 波多野成人无码精品69| 亚洲手机视频| 爱爱爱免费视频| 92久久| 好男人WWW一区二区三区| 国产一級A片免费看| 色情片免费看| 夜夜爽7777精品国产三级| 人人操人人爱人人妻| 爱爱电影无码| 影音先锋女人aV鲁色资源网站 | 欧美婷婷| 成人福利视频| 乱伦三级| 欧美熟妇精品一级A片视色| 中文字幕乱码中文字乱码影响大吗 | 欧美日韩在线视频免费| 久草久热| 黄网站在线免费| 久久伊思人在| 日韩一级片网站| 一级黄色免费视频| 激情视频综合网| 探花一区二区| 国产精品九九九九九九| 99精品视频免费在线观看| 日韩中文字幕专区| 国产69精品久久| 免费高清无码| 黄色成人在线观看视频| 三级片亚洲无码| 久久婷婷国产综合| 丰满人妻一区二区三区免费| 国产操逼的视频| 久久第一页| 久久久噜噜噜| 日本性爱无码| 亚洲综合91| 一级黄色视频网站| 中文字幕h| 91天天综合| 中文字幕激情精品| 国产精品久久久久久亚洲毛片| 在线免费小黄片| 人妻无码精品久久人妻成人| 狠狠色噜噜狠狠狠7777米奇网| 婷婷五月天成人社区| 国产精品久久7777777精品无码| 欧美影院亚洲| 日本黄色三级| 人妻AV一区| 性一区| 学生妹一级片| 日韩极品视频| 涩婷婷| 日本久久久久久久久视频在线观看| 伊人AV在线| 日韩无修正| 一道本无码视频| 北条麻妃在线视频| 日韩黄色片网站| 免费黄片视频在线观看| 一级黄色视频在线观看| 亚洲日韩视频在线观看| 久久久久久久| 99久久久久久久无码| 日韩无码乱码| 黄页视频网站| 中文字幕亚洲欧美| a视频免费在线观看| 精品在线免费观看| 天天操夜夜操| AV天堂手机| 美女人人操| 日日艹夜夜艹| 岛国免费AV| 中文字幕偷拍| 懂色av粉嫩AV蜜臀AV| 91一区二区在线播放精品| 久久综合无码内射国产| 久久久青草| 人人色在线| 一夲道无码专区av无码A片| 三级一区二区| 亚洲婷婷视频| 亚洲欧美卡通| 久久久久亚洲AV成人网人人软件| 日韩成人精品视频| 成人网在线视频| 国产黄网| 岛国av无码免费| 手机AV在线观看| 国产AV小电影| 久久久91精品国产一区苍井空| 午夜看黄片| 成人在线观看AV| 精品国产一二三区| 久久er99| 亚洲日韩av在线| 一区在线视频| 免看一级a一片| 亚洲一本之道| 亚洲色欲色欲www在线成人网| 91精品无码| 成年人免费黄色视频| 另类老妇性BBwBBw图片| 91香蕉国产在线观看软件| 中文字幕无码人妻| 日韩中文无码一级A片| 色逼逼网| 日本爱爱视频免费| 国产黄色录像| AV观看免费| 亚洲视频在线视频| 老司机免费视频| 三级黄色免费| 天天躁夜夜躁av| 男人色天堂网| 脓肿是什么原因引起的,该怎么治疗 | 91三级在线观看| 久久亚洲成人| 人人妻人人操人人爱| 婷婷精品免费| 免费黄色视频观看| 影音先锋人妻限定| 日韩成人不卡| 黄色成人网站在线播放| 北条麻妃无码视频| 91麻豆国产福利在线观看| 久久久久无码精品国产91福利 | 色播网址| 日韩免费看| 色墦五月丁香| 高潮喷水无码| 激情深爱| 日韩A人人| 动漫啪啪视频| 在线永久看片免费的视频| 強暴人妻一区二区三区| 国产成人精品无码区在线| 欧一美一色一伦一A片| 色噜噜狠狠色综无码久久合欧美 | 91秦先生在线播放| 8050午夜| 成人性爱自拍| 成人爱爱免费视频| 婷婷久久综合久色| 无码高清视频在线观看| 99国产精品久久久久久久成人| 韩国高清无码视频| 亚洲无码人妻一区| av青青草原| 91在线无码精品秘国产三年| 亚洲Japanese办公室制服 | 一区二区三区久久| 亚洲中文偷拍| 日本一区二区三区在线视频| 久久免费观看视频| 不卡无码免费视频| 久久精品国产精品| 久久久久久久性爱| 日本免费一二三区| 秋霞午夜视频| 国产精品9999久久久久仙踪林 | 伊人婷婷大香蕉| 四虎视频| 日韩午夜在线观看| AA片免费网站| 婷婷在线观看免费| 午夜成人AV| av色在线| 久久久久久久无码| 久久亚洲福利视频| 欧美日韩不卡视频| 欧美成人在线网站| 成人一区二区三区四区五区| jizz视频| 丁香五月亚洲综合| 午夜精品视频在线观看| 欧美h| 成人在线欧美| 囯产精品久久久久久久久久久久久久| 国产乱子伦-区二区三区熟睡91 | 久久精品免费观看| 黄色一级大片在线免费看国产| 久久久久国产视频| 欧美色图在线观看视频| 亚洲日韩Av无码中文字幕美国| 日本中文无码| 成人H动漫精品一区二区三区蘑菇| 狠狠操天天操| av三级片在线观看| 97免费视频在线观看| 国产久久在线| 天堂网2025| 玖玖成人| 国产精品高潮呻吟| 97视频在线| 色综合久久久无码中文字幕999| 北条麻妃99精彩视频| 一级A片亲子乱中文| 搞搞网日本9| 日韩一区二区在线视频| 亚洲韩国国产| 夜夜操天天操| AV老鸭窝| 美女被操免费网站| 影音先锋国产在线| 胖老板办公室沙发无套爆秘书| 高清无码二区| 亚洲精品鲁一鲁一区二区三区| 精品一区二区三区四区视频| 亚洲激情国产| 久草小视频| 婷婷色五月激情| 丁香色综合人妻| 亚洲无码在线视频播放| 激情开心站| 午夜无码福利| 久久伊思人在| gogogo视频在线观看黑人| 黄片无码在线观看| 亚洲AV永久无码国产精品久久 | 婷婷五月天成人社区| 亚洲色逼| 少妇搡BBBB搡BBB搡造水多/| 最新免费毛片| a片在线视频| 亚洲黄色视频在线观看网站| 天天日天天爽| 日韩一级二级三级| 国产91页| 日韩色情片| 伊人综合大香蕉| 99久久婷婷国产综合精品青牛牛 | 天堂网免费视频| 韩国精品无码一区二区三区18| 色噜噜人妻av中文字幕| 综合天堂网| 亚洲欧美视频在线| 西西444WWW无码视频软件功能介绍 | 国产婷婷色一区二区三区| 亚洲日逼网站| 国产在线观看免费成人视频| 456亚洲影院| 欧美色影院| 丁香色综合人妻| 欧洲一区二区三区| 麻豆一二三区| 亚洲色色视频| 色老汉视频| 亚洲天堂高清| 国产一级做a爱免费视频| 91免费在线| 亚洲专区在线| 美女一级A片| 夜夜嗨av无码一区二区三区| 欧美另类激情| 丁香六月啪啪| 激情婷婷丁香| 操逼网址| 日韩免费三级片| 中文字幕精品视频在线观看| 国产免费av在线观看| 欧美成人精品AAA| 中文字幕无码日韩| 亚洲男同tv| 最新久欠一区二区免费看| 一级片在线观看视频| 亚洲高清成人动漫| 国精产品一二三区| 国产精品毛片A√一区| 黄色国产在线观看| 最近中文字幕免费mv第一季歌词大全| 亚洲影音先锋在线| 欧美黄片免费视频| 毛片在线视频| 国产精品99久久久久久成人| 狠狠热视频| 免费观看日韩无码视频| 91一区二区三区| 1级毛片| 特级婬片A片AAA毛片AA做头 | 91精品人妻一区二| 欧美激情三区| 逼逼视频| 成人无码日本动漫电影| 久久国产大奶| 一区毛片| 美女91视频网站| 久久精品视频一区| 成人免费AV| 亚洲一区免费| 国产操逼片| 精品在线免费视频| 囯产精品久久久久久久久久辛辛 | 99re久久| 亚洲一级黄色视频| 无码人妻丰满熟妇区蜜桃| 国产91在线看| 久久久综合网| 欧美黄色大香蕉| 91精品国产综合久久久蜜臀酒店| 操人网站| 特级婬片AAAAAAA级| 日本无码网站| 国产99久久| 亚洲成人电影天堂| 汇聚全球淫荡熟女| 在线观看国产| 国产成人无码一区二区在线| 日韩激情无码一区二区| 丁香五月六月婷婷| 真人BBwBBWBBw另类视频 | 国产91在线亚洲| 99视频这里有精品| 久久国产一区二区三区| 九九精品网| 热久久最新| 四川少妇bbbb| 亚洲一线在线观看| 中文字幕AV在线| 亚洲人妻av| 亚洲日逼| 在线A视频| av东方在线| 鸡巴操骚逼视频| 欧美AAA大片| 日韩中文无码电影| 亚洲视频99| 亚洲激情偷拍| 欧美精品午夜福利无码| 驲韩在线视频免费观看| 一级久久| 国产精品视频播放| 国产精品天天干| 免费激情| 国产精品久久久久久久久久两年半| 亚洲最大的成人网站| 99热播| 久久艹逼| 国产视频一区二区三区四区五区| 欧美第二页| 免费视频久久| 超碰97免费在线| 久久嫩草国产成人一区| 国产丝袜人妖TS系列| 99精品无码视频| 日本在线一区| 欧美日韩不卡视频| www.丁香五月| 婷婷综合久久| 亚洲欧美卡通| 麻豆精品在线观看| 婷婷在线电影| 性天堂| 看黄色一级片| 99国产精品99久久久久久粉嫩| 琪琪色在线视频| 黄片亚洲| 天天综合天天干| 亚洲综合一区二区| 亚洲性爱中文字幕| 亚洲乱淫| 色五月丁香婷婷| 热逼视频| 色aV牛牛在线观看| 日韩AV三级片| 北条麻妃无码在线视频| 按摩性高湖婬AAA片A片中国| 91精品国产综合久久久蜜臀图片 | 偷拍777| 69国产精品| 中文字幕无码Av在线看| 日日干夜夜操| 99爱视频| 天堂成人在线视频| 亚洲人妻免费视频| 在线免费亚洲|