精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

一文帶你吃透定時(shí)任務(wù)框架

開發(fā) 前端
crontab 嚴(yán)格來說并不是屬于 java 內(nèi)的,它是 linux 自帶的一個(gè)工具,可以周期性地執(zhí)行某個(gè)shell腳本或命令。

一、介紹

說到定時(shí)任務(wù),相信大家都不陌生,在我們實(shí)際的工作中,用到定時(shí)任務(wù)的場(chǎng)景可以說非常的多,例如:

  • 雙 11 的 0 點(diǎn),定時(shí)開啟秒殺
  • 每月1號(hào),財(cái)務(wù)系統(tǒng)自動(dòng)拉取每個(gè)人的績效工資,用于薪資計(jì)算
  • 使用 TCP 長連接時(shí),客戶端按照固定頻率定時(shí)向服務(wù)端發(fā)送心跳請(qǐng)求

等等,定時(shí)器像水和空氣一般,普遍存在于各個(gè)場(chǎng)景中,在實(shí)際的業(yè)務(wù)開發(fā)中,基本上少不了定時(shí)任務(wù)的應(yīng)用。

總結(jié)起來,一般定時(shí)任務(wù)的表現(xiàn)有以下幾個(gè)特征:

1.在某個(gè)時(shí)刻觸發(fā),例如11.11號(hào)0點(diǎn)開啟秒殺

2.按照固定頻率周期性觸發(fā),例如每分鐘發(fā)送心跳請(qǐng)求

3.預(yù)約指定時(shí)刻開始周期性觸發(fā),例如從12.1號(hào)開始每天7點(diǎn)鬧鐘響起

說了這么多,也不BB了,下面我們就來點(diǎn)干活,列舉一些實(shí)際項(xiàng)目中使用的相關(guān)工具!

二、crontab 定時(shí)器

2.1、介紹

crontab 嚴(yán)格來說并不是屬于 java 內(nèi)的,它是 linux 自帶的一個(gè)工具,可以周期性地執(zhí)行某個(gè)shell腳本或命令。

由于 crontab 在實(shí)際開發(fā)中應(yīng)用比較多, 特別是對(duì)于運(yùn)維的人,crontab 命令是必須用到的命令,自動(dòng)化運(yùn)維中一定少不了它,而且 crontab 表達(dá)式跟我們后面要介紹的其他定時(shí)任務(wù)框架,例如 Quartz,Spring Schedule 的 cron 表達(dá)式類似,所以這里先介紹 crontab。

簡而言之,crontab 就是一個(gè)自定義定時(shí)器。

命令格式如下:

.---------------- minute (0 - 59)
|  .------------- hour (0 - 23)
|  |  .---------- day of month (1 - 31)
|  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
|  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) ...
|  |  |  |  |
*  *  *  *  *  command
  • 第一個(gè)參數(shù)(minute):代表一小時(shí)內(nèi)的第幾分,范圍 0-59。
  • 第二個(gè)參數(shù)(hour):代表一天中的第幾小時(shí),范圍 0-23。
  • 第三個(gè)參數(shù)(day):代表一個(gè)月中的第幾天,范圍 1-31。
  • 第四個(gè)參數(shù)(month):代表一年中第幾個(gè)月,范圍 1-12。
  • 第五個(gè)參數(shù)(week):代表星期幾,范圍 0-7 (0及7都是星期天)。
  • 第六個(gè)參數(shù)(command):所要執(zhí)行的指令。

具體應(yīng)用的時(shí)候,時(shí)間定義大概是長下面這個(gè)樣子!

# 每5分鐘執(zhí)行一次命令
*/5 * * * * Command
# 每小時(shí)的第5分鐘執(zhí)行一次命令
5 * * * * Command
# 指定每天下午的 6:30 執(zhí)行一次命令
30 18 * * * Command
# 指定每月8號(hào)的7:30分執(zhí)行一次命令
30 7 8 * * Command
# 指定每年的6月8日5:30執(zhí)行一次命令
30 5 8 6 * Command
# 指定每星期日的6:30執(zhí)行一次命令
30 6 * * 0 Command

2.2、具體示例

以centOS操作系統(tǒng)為例,創(chuàng)建一個(gè)定時(shí)任務(wù),每分鐘執(zhí)行某個(gè)指定shell腳本,過程如下!

  • 首先安裝 crond 相關(guān)服務(wù)
yum -y install cronie yum-cron
  • 編寫一個(gè)輸出當(dāng)前時(shí)間到日志的shell腳本
#創(chuàng)建一個(gè)test.sh腳本
vim /root/shell/test.sh

#腳本內(nèi)容如下,將內(nèi)容輸出到file.log文件
echo `date '+%Y-%m-%d %H:%M:%S'` >> /root/shell/file.log
  • 先執(zhí)行一下腳本,觀察內(nèi)容是否輸出到file.log文件
sh /root/shell/test.sh
  • 查看日志文件內(nèi)容
cat /root/shell/file.log

如果出現(xiàn)以下內(nèi)容,說明運(yùn)行正常!

圖片圖片

  • 接著再來創(chuàng)建一個(gè)定時(shí)任務(wù),每分鐘執(zhí)行一次test.sh
#編輯定時(shí)任務(wù)【刪除-添加-修改】
crontab -e
  • 在文件末尾加入如下信息
#每分鐘執(zhí)行一次test.sh腳本
*/1 * * * * sh /root/shell/test.sh
  • 如果想查定時(shí)任務(wù)是否加入,可以通過如下命令
#查看crontab定時(shí)任務(wù)
crontab -l

圖片圖片

  • 最后就是重啟定時(shí)任務(wù)
##重新載入配置
systemctl reload crond
#重啟服務(wù)
systemctl restart crond
  • 查看file.log文件實(shí)時(shí)輸出內(nèi)容,觀察test.sh腳本是否被執(zhí)行
tail -f /root/shell/file.log

從結(jié)果上看,運(yùn)行正常!

圖片圖片

  • 如果想查看定時(shí)任務(wù)日志,可通過如下命令進(jìn)行查看
tail -f /var/log/cron

如果想移除某個(gè)定時(shí)任務(wù),直接輸入crontab -e命令,并移除對(duì)應(yīng)的腳本,然后刷新配置、重啟服務(wù)即可!

如果想深入的了解crontab使用,可以參考這篇文章,里面總結(jié)得比較好, 這里就不再多說了。

三、java 自帶的定時(shí)器

3.1、Timer

Timer 定時(shí)器,由 jdk 提供的java.util.Timer和java.util.TimerTask兩個(gè)類組合實(shí)現(xiàn)。

其中TimerTask表示某個(gè)具體任務(wù),而Timer則是進(jìn)行調(diào)度任務(wù)處理。

實(shí)現(xiàn)過程也很簡單,示例如下:

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

public class TimerTest extends TimerTask {

    private String jobName;

    public TimerTest(String jobName) {
        this.jobName = jobName;
    }

    @Override
    public void run() {
        System.out.println("execute " + jobName);
    }

    public static void main(String[] args) {
        Timer timer = new Timer();
        long delay1 = 1 * 1000;
        long period1 = 1 * 1000;
        // 從現(xiàn)在開始 1 秒鐘之后,每隔 1 秒鐘執(zhí)行一次 job1
        timer.schedule(new TimerTest("job1"), delay1, period1);

        long delay2 = 2 * 1000;
        long period2 = 2 * 1000;
        // 從現(xiàn)在開始 2 秒鐘之后,每隔 2 秒鐘執(zhí)行一次 job2
        timer.schedule(new TimerTest("job2"), delay2, period2);
    }
}

輸出結(jié)果:

execute job1
execute job2
execute job1
execute job1
execute job2
execute job1
execute job1
execute job2
...

Timer 的優(yōu)點(diǎn)在于簡單易用,由于所有任務(wù)都是由同一個(gè)線程來調(diào)度,因此所有任務(wù)都是串行執(zhí)行的,同一時(shí)間只能有一個(gè)任務(wù)在執(zhí)行,前一個(gè)任務(wù)的延遲或異常都將會(huì)影響到之后的任務(wù)。

具體原因如下:

  • 1.當(dāng)一個(gè)線程拋出異常時(shí),整個(gè) Timer 都會(huì)停止運(yùn)行。例如上面的 job1 拋出異常的話,job2 也不會(huì)再跑了
  • 當(dāng)一個(gè)線程里面處理的時(shí)間非常長的時(shí)候,會(huì)影響其他 job 的調(diào)度。例如,如果 job1 處理的時(shí)間要 1 分鐘, 那么 job2 至少要等 1 分鐘之后才能跑。

基于上面的原因,Timer 現(xiàn)在生產(chǎn)環(huán)境中都不在使用!

3.2、ScheduledExecutor

鑒于 Timer 的上述缺陷,從 Java 5 開始,推出了基于線程池設(shè)計(jì)的 ScheduledExecutor。

其設(shè)計(jì)思想是,每一個(gè)被調(diào)度的任務(wù)都會(huì)由線程池中一個(gè)線程來管理執(zhí)行,因此任務(wù)是并發(fā)執(zhí)行的,相互之間不會(huì)受到干擾。需要注意的是,只有當(dāng)任務(wù)的執(zhí)行時(shí)間到來時(shí),ScheduedExecutor 才會(huì)真正啟動(dòng)一個(gè)線程,其余時(shí)間 ScheduledExecutor 都是在輪詢?nèi)蝿?wù)的狀態(tài)。

實(shí)現(xiàn)過程,示例如下:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorTest implements Runnable {

    private String jobName;

    public ScheduledExecutorTest(String jobName) {
        this.jobName = jobName;
    }

    @Override
    public void run() {
        System.out.println("execute " + jobName);
    }

    public static void main(String[] args) {
        //設(shè)置10個(gè)核心線程
        ScheduledExecutorService service = Executors.newScheduledThreadPool(10);

        long initialDelay1 = 1;
        long period1 = 1;

        // 從現(xiàn)在開始1秒鐘之后,每隔1秒鐘執(zhí)行一次job1
        service.scheduleAtFixedRate(
                new ScheduledExecutorTest("job1"), initialDelay1,
                period1, TimeUnit.SECONDS);

        long initialDelay2 = 2;
        long delay2 = 2;
        // 從現(xiàn)在開始2秒鐘之后,每隔2秒鐘執(zhí)行一次job2
        service.scheduleWithFixedDelay(
                new ScheduledExecutorTest("job2"), initialDelay2,
                delay2, TimeUnit.SECONDS);
    }
}

輸出結(jié)果:

execute job1
execute job1
execute job2
execute job1
execute job1
execute job2
execute job1

在 ScheduledExecutorService 中,由initialDelay、delay和TimeUnit三個(gè)參數(shù)決定任務(wù)的執(zhí)行頻率。

其中:

  • TimeUnit:表示執(zhí)行的單位,例如:毫秒、秒、分、小時(shí)、天...
  • initialDelay:表示從現(xiàn)在開始多少TimeUnit后執(zhí)行任務(wù)
  • delay:表示任務(wù)執(zhí)行周期,每隔多少TimeUnit執(zhí)行一次任務(wù)

從 api 上可以看到,ScheduledExecutorService 的出現(xiàn),完全可以替代 Timer  ,同時(shí)完美的解決上面所說的 Timer 存在的兩個(gè)問題!

  • 當(dāng)任務(wù)拋異常時(shí),即使異常沒有被捕獲, 線程池也還會(huì)新建線程,所以定時(shí)任務(wù)不會(huì)停止
  • 由于 ScheduledExecutorService 是不同線程處理不同的任務(wù),因此不管一個(gè)線程的運(yùn)行時(shí)間有多長,都不會(huì)影響到另外一個(gè)線程的運(yùn)行

但是 ScheduledExecutorService 也不是萬能的,比如我想每月1號(hào)統(tǒng)計(jì)一次報(bào)表、每季度月末統(tǒng)計(jì)銷售額等等這樣的需求。

你會(huì)發(fā)現(xiàn)使用 ScheduledExecutorService 實(shí)現(xiàn)的時(shí)候,每次任務(wù)執(zhí)行之后,你需要從當(dāng)前時(shí)間開始出下一次執(zhí)行時(shí)間的間隔,而且每次都要重算,非常麻煩!

遇到這樣的需求,就需要一個(gè)更加完善的任務(wù)調(diào)度框架來解決這些復(fù)雜的調(diào)度問題。

而我們所熟悉的開源框架 Quartz 在這方面就提供了強(qiáng)大的支持。

四、第三方定時(shí)器

4.1、Quartz

quartz 在 java 項(xiàng)目中應(yīng)用非常的廣,市面上很多的開源調(diào)度框架也基本都是直接或間接基于這個(gè)框架來開發(fā)的。

下面我們就通過一個(gè)例子,來簡單地認(rèn)識(shí)一下它。

  • 引入quartz包
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>
  • 編寫示例代碼
public class QuartzTest implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }

    public static void main(String[] args) throws SchedulerException {
        // 創(chuàng)建一個(gè)Scheduler
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        // 啟動(dòng)Scheduler
        scheduler.start();

        // 新建一個(gè)Job, 指定執(zhí)行類是QuartzTest, 指定一個(gè)K/V類型的數(shù)據(jù), 指定job的name和group
        JobDetail job = JobBuilder.newJob(QuartzTest.class)
                .usingJobData("jobData", "test")
                .withIdentity("myJob", "myJobGroup")
                .build();

        // 新建一個(gè)Trigger, 表示JobDetail的調(diào)度計(jì)劃, 這里的cron表達(dá)式是 每1秒執(zhí)行一次
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger", "myTriggerGroup")
                .startNow()
                .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
                .build();

        // 讓scheduler開始調(diào)度這個(gè)job, 按trigger指定的計(jì)劃
        scheduler.scheduleJob(job, trigger);
    }
}

輸出結(jié)果:

2020-11-09 21:38:40
2020-11-09 21:38:45
2020-11-09 21:38:50
2020-11-09 21:38:55
2020-11-09 21:39:00
2020-11-09 21:39:05
2020-11-09 21:39:10
...

當(dāng)然,你還可以從JobExecutionContext對(duì)象中,獲取上文usingJobData()方法中設(shè)置的值。

@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
    //從context中獲取instName,groupName以及dataMap
    String jobName = context.getJobDetail().getKey().getName();
    String groupName = context.getJobDetail().getKey().getGroup();
    JobDataMap dataMap = context.getJobDetail().getJobDataMap();
    //從dataMap中獲取myDescription,myValue以及myArray
    String value = dataMap.getString("jobData");
    System.out.println("jobName:" + jobName + ",groupName:" + groupName + ",jobData:" + value);
}

輸出結(jié)果:

jobName:myJob,groupName:myJobGroup,jobData:test

在 Quartz 工具包中,設(shè)計(jì)的核心類主要包括 Scheduler, Job 以及 Trigger。

  • Scheduler:可以理解為是一個(gè)具體的調(diào)度實(shí)例,用來調(diào)度任務(wù)
  • JobDetail:定義具體作業(yè)的實(shí)例,進(jìn)一步封裝和拓展了 Job 功能,其中 Job 是一個(gè)接口,類似上面的 TimerTask
  • Trigger:設(shè)置任務(wù)調(diào)度策略。例如多久執(zhí)行一次,什么時(shí)候執(zhí)行,以什么頻率執(zhí)行等等

相比 JDK 提供的任務(wù)調(diào)度服務(wù),Quartz 最明顯的一個(gè)特點(diǎn)就是將任務(wù)調(diào)度者、任務(wù)具體實(shí)例、任務(wù)調(diào)度策略進(jìn)行三方解耦,這么做的優(yōu)點(diǎn)在于同一個(gè) Job 可以綁定多個(gè)不同的 Trigger,同一個(gè) Trigger 也可以調(diào)度多個(gè) Job,配置靈活性非常強(qiáng)。

Trigger 同時(shí)還支持cron表達(dá)式,在任務(wù)調(diào)度時(shí)間配置方面,更加靈活。

當(dāng)然,Quartz 的用途不僅僅在單例服務(wù)上,在分布式調(diào)度方面也同樣應(yīng)用非常廣,由于篇幅原因,關(guān)于 Quartz 的詳細(xì)使用介紹,我們會(huì)在后期的文章中詳細(xì)深入分析。

4.2、Spring Schedule

與 Quartz 齊名的還有我們所熟悉的 Spring Schedule,由 Spring 原生提供支持。

實(shí)現(xiàn)上,Spring 中使用定時(shí)任務(wù)也非常簡單。

4.2.1、基于 XML 配置
  • 在springApplication.xml配置文件中加入如下信息
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
    xmlns:p="http://www.springframework.org/schema/p"  
    xmlns:task="http://www.springframework.org/schema/task"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:aop="http://www.springframework.org/schema/aop"   
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd    
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd    
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd    
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd    
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">  

    <!-- 定時(shí)器開關(guān)-->  
    <task:annotation-driven />

    <!-- 將TestTask注入ioc-->
    <bean id="myTask" class="com.spring.task.TestTask"></bean>

    <!-- 定時(shí)調(diào)度方法配置-->
    <task:scheduled-tasks>
        <!-- 這里表示的是每隔5秒執(zhí)行一次 -->
        <task:scheduled ref="myTask" method="show" cron="*/5 * * * * ?" />
        <!-- 這里表示的是每隔10秒執(zhí)行一次 -->
        <task:scheduled ref="myTask" method="print" cron="*/10 * * * * ?"/>
    </task:scheduled-tasks>

    <!-- 自動(dòng)掃描的包名 -->
    <context:component-scan base-package="com.spring.task" />

</beans>
  • 定義自己的任務(wù)執(zhí)行邏輯
package com.spring.task;

/**
 * 定義任務(wù)
 */
public class TestTask {

    public void show() {
        System.out.println("show method 1");
    }

    public void print() {
        System.out.println("print method 1");
    }
}
4.2.2、基于注解配置

基于注解的配置,可以直接在方法上配置相應(yīng)的調(diào)度策略,相比xml的方式更加簡潔。

  • 實(shí)現(xiàn)過程如下
package com.spring.task;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * 基于注解的定時(shí)器
 */
@Component
public class TestTask2 {

    /**
     * 定時(shí)計(jì)算。每隔5秒執(zhí)行一次
     */
    @Scheduled(cron = "*/5 * * * * ?")
    public void show() {
        System.out.println("show method 2");
    }

    /**
     * 啟動(dòng)1分鐘后執(zhí)行,之后每隔10秒執(zhí)行一次
     */
    @Scheduled(initialDelay = 60*1000, fixedRate = 10*1000)
    public void print() {
        System.out.println("print method 2");
    }
}
4.2.3、Spring Boot 定時(shí)任務(wù)應(yīng)用

如果在 Spring Boot 項(xiàng)目中,使用就更加方便了。

  • 首先在程序入口啟動(dòng)類添加@EnableScheduling,開啟定時(shí)任務(wù)功能
@SpringBootApplication
@EnableScheduling
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
  • 編寫定時(shí)任務(wù)邏輯
@Component
public class TestTask3 {

    private int count=0;

    @Scheduled(crnotallow="*/5 * * * * ?")
    private void process() {
        System.out.println("this is scheduler task running  "+(count++));
    }
}

輸出結(jié)果:

this is scheduler task running  0
this is scheduler task running  1
this is scheduler task running  2
...
4.2.4、任務(wù)執(zhí)行規(guī)則

最后,我們來看看 Spring Schedule 的任務(wù)執(zhí)行規(guī)則,打開@Scheduled注解類,源碼如下:

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {

    String cron() default "";

    String zone() default "";

    long fixedDelay() default -1;

    String fixedDelayString() default "";

    long fixedRate() default -1;

    String fixedRateString() default "";

    long initialDelay() default -1;

    String initialDelayString() default "";
}

從方法上可以看出,@Scheduled注解中可以傳 8 種參數(shù):

  • cron:指定 cron 表達(dá)式
  • zone:默認(rèn)使用服務(wù)器默認(rèn)時(shí)區(qū)。可以設(shè)置為java.util.TimeZone中的zoneId
  • fixedDelay:從上一個(gè)任務(wù)完成開始到下一個(gè)任務(wù)開始的間隔,單位毫秒
  • fixedDelayString:同上,時(shí)間值是String類型
  • fixedRate:從上一個(gè)任務(wù)開始到下一個(gè)任務(wù)開始的間隔,單位毫秒
  • fixedRateString:同上,時(shí)間值是String類型
  • initialDelay:任務(wù)首次執(zhí)行延遲的時(shí)間,單位毫秒
  • initialDelayString:同上,時(shí)間值是String類型

其中用的最多的就是cron表達(dá)式,下面我們就一起來看看如何來編寫配置。

4.2.5、Cron 表達(dá)式

Spring 的 cron 表達(dá)式和 Quartz 的 cron 表達(dá)式基本都是通用的,但是與 linux 下 crontab 的 cron 表達(dá)式是有一定區(qū)別的,它可以直接到秒級(jí)別。

cron 表達(dá)式結(jié)構(gòu):

.---------------------- seconds(0 - 59)
|  .------------------- minute (0 - 59)
|  |  .---------------- hour (0 - 23)
|  |  |  .------------- day of month (1 - 31)
|  |  |  |  .---------- month (1 - 12)
|  |  |  |  |  .------- Day-of-Week (1 - 7) 
|  |  |  |  |  |  .---- year (1970 - 2099) ...
|  |  |  |  |  |  |
*  *  *  *  *  ?  *

具體樣例如下:

圖片圖片

在 cron 表達(dá)式中不區(qū)分大小寫,更多配置可以參考這里。

還可以在線解析cron表達(dá)式進(jìn)行測(cè)試。

圖片圖片

4.3、elastic-job

elastic-job 是當(dāng)當(dāng)基于 quartz 二次開發(fā)而開源的一個(gè)分布式彈性作業(yè)框架,功能十分強(qiáng)大。

主要功能:

  • 分布式:重寫 Quartz 基于數(shù)據(jù)庫的分布式功能,改用 Zookeeper 實(shí)現(xiàn)注冊(cè)中心。
  • 并行調(diào)度:采用任務(wù)分片方式實(shí)現(xiàn)。將一個(gè)任務(wù)拆分為n個(gè)獨(dú)立的任務(wù)項(xiàng),由分布式的服務(wù)器并行執(zhí)行各自分配到的分片項(xiàng)。
  • 彈性擴(kuò)容縮容:將任務(wù)拆分為 n 個(gè)任務(wù)項(xiàng)后,各個(gè)服務(wù)器分別執(zhí)行各自分配到的任務(wù)項(xiàng)。一旦有新的服務(wù)器加入集群,或現(xiàn)有服務(wù)器下線,elastic-job將在保留本次任務(wù)執(zhí)行不變的情況下,下次任務(wù)開始前觸發(fā)任務(wù)重分片。
  • 集中管理:采用基于Zookeeper的注冊(cè)中心,集中管理和協(xié)調(diào)分布式作業(yè)的狀態(tài),分配和監(jiān)聽。外部系統(tǒng)可直接根據(jù)Zookeeper的數(shù)據(jù)管理和監(jiān)控elastic-job。
  • 定制化流程型任務(wù):作業(yè)可分為簡單和數(shù)據(jù)流處理兩種模式,數(shù)據(jù)流又分為高吞吐處理模式和順序性處理模式,其中高吞吐處理模式可以開啟足夠多的線程快速的處理數(shù)據(jù),而順序性處理模式將每個(gè)分片項(xiàng)分配到一個(gè)獨(dú)立線程,用于保證同一分片的順序性,這點(diǎn)類似于kafka的分區(qū)順序性。

由于 elastic-job 是基于 Zookeeper 實(shí)現(xiàn)集群調(diào)度,因此在使用它之前,需要先搭建好 Zookeeper 服務(wù)器,網(wǎng)上教程很多,在此不過多介紹。

elastic-job 具體簡單實(shí)現(xiàn)過程如下!

  • 引入相關(guān) elastic-job 依賴
<dependencies>
    <!-- 引入elastic-job-lite核心模塊 -->
    <dependency>
        <groupId>com.dangdang</groupId>
        <artifactId>elastic-job-lite-core</artifactId>
        <version>2.0.5</version>
    </dependency>
    <!-- 使用springframework自定義命名空間時(shí)引入 -->
    <dependency>
        <groupId>com.dangdang</groupId>
        <artifactId>elastic-job-lite-spring</artifactId>
        <version>2.0.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.9</version>
    </dependency>
</dependencies>
  • 定義job
public class MyElasticJob implements SimpleJob {

    public void execute(ShardingContext context) {
        System.out.println(context.toString());
        switch (context.getShardingItem()) {
            case 0:
                System.out.println("------------->>>>0");
                break;
            case 1:
                System.out.println("------------->>>>1");
                break;
            case 2:
                System.out.println("------------->>>>2");
                break;
            default:
                System.out.println("------------->>>>default");
                break;
        }
    }


    public static void main(String[] args) {
        new JobScheduler(createRegistryCenter(), createJobConfiguration()).init();
    }

    private static CoordinatorRegistryCenter createRegistryCenter() {
        //配置ZK注冊(cè)中心地址
        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration("10.211.108.160:2181", "elastic-job-demo"));
        regCenter.init();
        return regCenter;
    }
    private static LiteJobConfiguration createJobConfiguration() {
        JobCoreConfiguration simpleCoreConfig = JobCoreConfiguration.newBuilder("demoSimpleJob", "0/15 * * * * ?", 10).build();
        // 定義SIMPLE類型配置
        SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(simpleCoreConfig, MyElasticJob.class.getCanonicalName());
        // 定義Lite作業(yè)根配置
        LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).build();
        return simpleJobRootConfig;
    }
}

具體詳細(xì)使用,可以參考官方網(wǎng)站。

4.4、xxl-job

xxl-job 是被廣泛使用的另外一款使用的分布式任務(wù)調(diào)度框架,出自大眾點(diǎn)評(píng)許雪里(xxl 就是作者名字的拼音首字母)的開源項(xiàng)目,官網(wǎng)上介紹這是一個(gè)輕量級(jí)分布式任務(wù)調(diào)度框架,其核心設(shè)計(jì)目標(biāo)是開發(fā)迅速、學(xué)習(xí)簡單、輕量級(jí)、易擴(kuò)展。

圖片圖片

跟elasticjob不同,xxl-job 環(huán)境依賴于mysql,不用 ZooKeeper,這也是最大的不同。早起的 xxljob 也是基于 quartz 開發(fā)的,不過現(xiàn)在慢慢去 quartz 化了,改成自研的調(diào)度模塊。

xxl-job 具體簡單實(shí)現(xiàn)過程如下!

  • 引入相關(guān) xxl-job 依賴
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>com.xuxueli</groupId>
        <artifactId>xxl-job-core</artifactId>
        <version>2.2.0</version>
    </dependency>
</dependencies>
  • 在application.properties添加相關(guān)配置
# web port
server.port=8081
# log config
logging.cnotallow=classpath:logback.xml
spring.application.name=xxljob-demo
### 調(diào)度中心部署跟地址 [選填]:如調(diào)度中心集群部署存在多個(gè)地址則用逗號(hào)分隔。執(zhí)行器將會(huì)使用該地址進(jìn)行"執(zhí)行器心跳注冊(cè)"和"任務(wù)結(jié)果回調(diào)";為空則關(guān)閉自動(dòng)注冊(cè);
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
### 執(zhí)行器通訊TOKEN [選填]:非空時(shí)啟用;
xxl.job.accessToken=
### 執(zhí)行器AppName [選填]:執(zhí)行器心跳注冊(cè)分組依據(jù);為空則關(guān)閉自動(dòng)注冊(cè)
xxl.job.executor.appname=xxl-job-demo
### 執(zhí)行器注冊(cè) [選填]:優(yōu)先使用該配置作為注冊(cè)地址,為空時(shí)使用內(nèi)嵌服務(wù) ”IP:PORT“ 作為注冊(cè)地址。從而更靈活的支持容器類型執(zhí)行器動(dòng)態(tài)IP和動(dòng)態(tài)映射端口問題。
xxl.job.executor.address=
### 執(zhí)行器IP [選填]:默認(rèn)為空表示自動(dòng)獲取IP,多網(wǎng)卡時(shí)可手動(dòng)設(shè)置指定IP,該IP不會(huì)綁定Host僅作為通訊實(shí)用;地址信息用于 "執(zhí)行器注冊(cè)" 和 "調(diào)度中心請(qǐng)求并觸發(fā)任務(wù)";
xxl.job.executor.ip=
### 執(zhí)行器端口號(hào) [選填]:小于等于0則自動(dòng)獲取;默認(rèn)端口為9999,單機(jī)部署多個(gè)執(zhí)行器時(shí),注意要配置不同執(zhí)行器端口;
xxl.job.executor.port=9999
### 執(zhí)行器運(yùn)行日志文件存儲(chǔ)磁盤路徑 [選填] :需要對(duì)該路徑擁有讀寫權(quán)限;為空則使用默認(rèn)路徑;
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### 執(zhí)行器日志文件保存天數(shù) [選填] : 過期日志自動(dòng)清理, 限制值大于等于3時(shí)生效; 否則, 如-1, 關(guān)閉自動(dòng)清理功能;
xxl.job.executor.logretentinotallow=10
  • 編寫一個(gè)配置類XxlJobConfig
@Configuration
public class XxlJobConfig {
    private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;
    @Value("${xxl.job.accessToken}")
    private String accessToken;
    @Value("${xxl.job.executor.appname}")
    private String appname;
    @Value("${xxl.job.executor.address}")
    private String address;
    @Value("${xxl.job.executor.ip}")
    private String ip;
    @Value("${xxl.job.executor.port}")
    private int port;
    @Value("${xxl.job.executor.logpath}")
    private String logPath;
    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;

    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setAddress(address);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
        return xxlJobSpringExecutor;
    }
}
  • 編寫具體任務(wù)類XxlJobDemoHandler
@Component
public class XxlJobDemoHandler {
    /**
     * Bean模式,一個(gè)方法為一個(gè)任務(wù)
     * 1、在Spring Bean實(shí)例中,開發(fā)Job方法,方式格式要求為 "public ReturnT<String> execute(String param)"
     * 2、為Job方法添加注解 "@XxlJob(value="自定義jobhandler名稱", init = "JobHandler初始化方法", destroy = "JobHandler銷毀方法")",注解value值對(duì)應(yīng)的是調(diào)度中心新建任務(wù)的JobHandler屬性的值。
     * 3、執(zhí)行日志:需要通過 "XxlJobLogger.log" 打印執(zhí)行日志;
     */
    @XxlJob("demoJobHandler")
    public ReturnT<String> demoJobHandler(String param) throws Exception {
        XxlJobLogger.log("java, Hello World~~~");
        XxlJobLogger.log("param:" + param);
        return ReturnT.SUCCESS;
    }
}

寫完之后啟動(dòng)服務(wù),然后可以打開管理界面,找到執(zhí)行器管理,添加執(zhí)行器。

圖片圖片

接著到任務(wù)管理,添加任務(wù)。

圖片

最后我們可以到任務(wù)管理去測(cè)試一下,運(yùn)行demoJobHandler。

圖片圖片

圖片圖片

點(diǎn)擊保存后,會(huì)立即執(zhí)行。點(diǎn)擊查看日志,可以看到任務(wù)執(zhí)行的歷史日志記錄

圖片圖片

這就是簡單的Demo演示,具體詳細(xì)使用,可以參考官方網(wǎng)站。

五、總結(jié)

本文主要圍繞定時(shí)調(diào)度器的理論知識(shí)和用法做了一次知識(shí)的總結(jié),如果有理解不對(duì)的地方,歡迎大家留言指出。

六、參考

1、https://juejin.im/post/6844904002606350343

2、https://developer.ibm.com/zh/languages/java/articles/j-lo-taskschedule/

3、https://www.cnblogs.com/linjiqin/p/11720673.html

4、https://www.cnkirito.moe/timer/

5、https://cloud.tencent.com/developer/article/1138669

6、https://developer.aliyun.com/article/775305

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2024-03-12 11:39:30

Python開發(fā)

2019-12-25 15:10:00

MySQL事件數(shù)據(jù)庫

2025-07-02 04:00:00

2020-02-07 11:07:53

數(shù)組鏈表單鏈表

2023-11-20 08:18:49

Netty服務(wù)器

2022-12-20 07:39:46

2023-12-21 17:11:21

Containerd管理工具命令行

2023-07-31 08:18:50

Docker參數(shù)容器

2023-11-06 08:16:19

APM系統(tǒng)運(yùn)維

2021-05-29 10:11:00

Kafa數(shù)據(jù)業(yè)務(wù)

2022-11-11 19:09:13

架構(gòu)

2023-01-16 08:49:20

RocketMQ定時(shí)任務(wù)源代

2021-04-27 11:28:21

React.t事件元素

2023-10-27 08:15:45

2023-11-08 08:15:48

服務(wù)監(jiān)控Zipkin

2022-02-24 07:34:10

SSL協(xié)議加密

2024-02-19 00:00:00

分布式定時(shí)任務(wù)框架

2022-05-16 10:49:28

網(wǎng)絡(luò)協(xié)議數(shù)據(jù)

2023-03-06 21:29:41

mmap技術(shù)操作系統(tǒng)

2022-04-08 09:01:14

CSS自定義屬性前端
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

在线观看你懂的视频| 日本10禁啪啪无遮挡免费一区二区| 九九热视频在线免费观看| 日韩国产大片| 亚洲自拍偷拍综合| 老司机精品福利在线观看| 成人午夜精品视频| 91成人免费| 亚洲大胆人体av| 99视频在线免费| av免费在线观看网址| 99久久精品国产导航| 国产精品入口夜色视频大尺度| 中文字幕美女视频| 超碰97久久| 欧美伊人久久大香线蕉综合69| 91免费视频黄| 欧洲一级在线观看| 国产一区视频在线看| 7777精品久久久久久| 三级黄色免费观看| 女同另类激情重口| 91精品欧美综合在线观看最新 | 中文字幕高清一区| 国产精品久久久久久久久久直播| 91黑人精品一区二区三区| 综合色一区二区| 国产一区二区免费| 亚洲香蕉中文网| 免费成人高清在线视频| 精品国产成人av| 香蕉视频免费版| 国产乱理伦片a级在线观看| 国产69精品久久777的优势| 国产精品久久久久影院日本| 久久精品国产亚洲av无码娇色| av亚洲在线观看| 亚洲第一色在线| 激情文学亚洲色图| 不卡亚洲精品| 亚洲一区二区美女| 国产又黄又爽免费视频| av中文天堂在线| 久久久久久毛片| 精品乱色一区二区中文字幕| 超碰福利在线观看| 国产老妇另类xxxxx| 国产精品嫩草影院久久久| 你懂的国产在线| 亚洲国产高清一区二区三区| 欧美大成色www永久网站婷| 黄色av片三级三级三级免费看| 天堂俺去俺来也www久久婷婷 | 无码精品视频一区二区三区 | 午夜视频在线播放| 成人美女视频在线观看18| 91色精品视频在线| 国产精品无码一区二区桃花视频| 蜜臀av一区二区在线免费观看| 欧美中文字幕在线观看| 日韩成人免费在线观看| 亚洲精品免费观看| 97精品国产97久久久久久免费| 久一区二区三区| 欧美日韩国产色综合一二三四| 不卡av电影院| 午夜激情福利网| 亚洲国产一区二区在线观看| 另类少妇人与禽zozz0性伦| 日韩欧美国产成人精品免费| 91精品国产调教在线观看| 久久久999精品视频| 国产精品免费人成网站酒店| 久久久久久久久丰满| 久久精品国产亚洲精品2020| 特一级黄色录像| 综合一区在线| 久久久天堂国产精品女人| 久久激情免费视频| 一区二区91| 青青a在线精品免费观看| 成人a v视频| 蜜桃视频免费观看一区| 91欧美日韩一区| 亚洲精品福利网站| 91丨porny丨国产| 五月天色一区| а√资源新版在线天堂| 亚洲成人精品| 欧美精品做受xxx性少妇| 久久国产一级片| 性伦欧美刺激片在线观看| 国产福利视频一区二区| 亚洲一区二区三区高清视频| 国内精品在线播放| 国产一区二区三区四区五区在线| 亚欧洲精品视频| 国产精品热久久久久夜色精品三区| 在线码字幕一区| 免费在线看污片| 91激情五月电影| 国内av免费观看| 亚欧洲精品视频在线观看| 中文字幕av一区| 久草视频手机在线观看| 久久亚洲风情| 亚洲自拍小视频| 欧美女优在线| 亚洲男人的天堂网| 成人在线免费播放视频| 无人区乱码一区二区三区| 日韩精品视频免费专区在线播放| 99久久99久久精品免费看小说.| 午夜激情一区| 国产精品久久久久久久久久久久久 | 国产欧美韩国高清| 欧美 中文字幕| 国产精品国产三级国产| 欧美精品久久久久久久久久久| 亚洲精品粉嫩美女一区| 欧美r级在线观看| 长河落日免费高清观看| 国产婷婷精品| 成人18视频| 在线播放毛片| 一本一道久久a久久精品综合蜜臀| 亚洲综合123| 激情五月色综合国产精品| 久久久久一本一区二区青青蜜月| 又骚又黄的视频| 久久综合999| a级黄色小视频| 国产精品3区| 一本一本久久a久久精品综合小说| 久久精品国产亚洲AV无码男同 | 欧美激情videoshd| 91成品人影院| 欧美激情一区二区三区四区| 天天夜碰日日摸日日澡性色av| 国产一区二区三区国产精品| 在线播放日韩精品| 黄色免费av网站| 99国产精品久久| 欧美久久在线观看| av不卡一区二区| 欧美精品一本久久男人的天堂| 亚洲天堂自拍偷拍| 亚洲国产精品ⅴa在线观看| 欧美综合在线观看视频| 亚洲综合福利| 欧美在线观看网址综合| 亚洲老妇色熟女老太| 亚洲激情中文1区| 污污视频在线免费| 欧美在线资源| 亚洲一区二区中文| 直接在线观看的三级网址| 欧美一级理论性理论a| 日韩成人短视频| 国产美女精品在线| 欧美与动交zoz0z| 日本一区二区三区视频在线看 | av免费不卡国产观看| 欧美精品一区二区三| 欧美日韩中文视频| 成人动漫av在线| 欧美亚洲精品一区二区| 人人香蕉久久| 情事1991在线| 波多野结衣在线影院| 欧美精品在线一区二区三区| 小泽玛利亚一区| 国产一区二区三区免费| www.日本三级| 日日夜夜精品| 伊人久久免费视频| 国产三级午夜理伦三级| 亚洲专区一二三| 加勒比精品视频| 日韩中文字幕麻豆| 中文字幕乱码一区二区三区| 日本成人手机在线| 57pao精品| 999在线视频| 日韩一级黄色大片| 亚洲久久在线观看| 国产精品毛片大码女人| 岛国大片在线免费观看| aa级大片欧美三级| 五月天亚洲综合情| 97品白浆高清久久久久久| 26uuu另类亚洲欧美日本老年| 精品999视频| 欧美精品久久久久久久多人混战 | 久久久久久国产精品美女| 三级国产在线观看| 欧美放荡的少妇| 日本系列第一页| 欧美国产日韩精品免费观看| 日本女人黄色片| 免费精品视频| 国产日本欧美在线| 欧美成人一区在线观看| 国产精品最新在线观看| 丰满大乳少妇在线观看网站 | 亚洲精品中文字幕在线播放| 美女网站色91| 欧美视频在线免费播放| 97人人精品| 久久久av水蜜桃| 国产亚洲精aa在线看| 国产97在线观看| 人妖欧美1区| 中文字幕亚洲无线码a| 人妻少妇一区二区三区| 欧美亚洲国产一区二区三区va| 久久婷婷一区二区| 国产精品卡一卡二卡三| 国产艳俗歌舞表演hd| 国产美女av一区二区三区| 国内自拍视频网| 中文高清一区| 欧美精品一区二区性色a+v| 久草成人在线| 久久99精品久久久久久水蜜桃| 国产一区二区在线观| 国产精品麻豆va在线播放| 黄色视屏在线免费观看| 欧美成人剧情片在线观看| 91高清在线| 亚洲视频在线免费观看| 天天舔天天干天天操| 日韩一级黄色大片| 国产一区二区三区中文字幕| 色噜噜夜夜夜综合网| 激情五月色婷婷| 亚洲国产色一区| 欧美激情图片小说| 国产精品久久毛片| 人妻av无码一区二区三区| 99re这里只有精品首页| 成人做爰www看视频软件| 国产米奇在线777精品观看| 亚洲欧美日韩精品一区| 日本不卡的三区四区五区| 粉嫩虎白女毛片人体| 久久久夜精品| 日韩精品免费播放| 久久亚洲精品伦理| 免费男同深夜夜行网站| 久久一二三四| 亚洲 欧美 日韩 国产综合 在线| 黄色成人在线网址| 国产av熟女一区二区三区 | av中文字幕在线不卡| 野战少妇38p| 波多野结衣在线aⅴ中文字幕不卡| 第一页在线视频| 国产美女视频一区| 精品国产午夜福利在线观看| 国内不卡的二区三区中文字幕| 中文字幕22页| 国产一区不卡在线| 无码人妻一区二区三区免费n鬼沢 久久久无码人妻精品无码 | 丝袜美腿诱惑一区二区三区| 欧亚精品中文字幕| 成人软件在线观看| 国产精品久久久久久久久久新婚 | 亚洲国产日韩a在线播放性色| 九九视频免费看| 亚洲成人av电影在线| 日韩毛片在线播放| 色婷婷一区二区三区四区| 国产一级片av| 欧美日韩国产电影| a天堂在线观看视频| 亚洲精品在线免费观看视频| 亚洲欧美色视频| 在线观看视频99| 九义人在线观看完整免费版电视剧| 欧美xxxx18国产| а√天堂8资源中文在线| 欧美在线视频免费| 四虎国产精品免费久久5151| 亚洲专区在线视频| 奇米777国产一区国产二区| 色999日韩自偷自拍美女| 一区二区三区四区在线观看国产日韩 | 日韩中文字幕av| 久久bbxx| 97国产精品免费视频| 色成人免费网站| 91丝袜脚交足在线播放| 网红女主播少妇精品视频| 亚洲欧美综合一区| 国产精品va| 91香蕉视频污版| 国产一区二区成人久久免费影院| 91精品又粗又猛又爽| 国产欧美精品一区| 久久久久久久蜜桃| 欧美一a一片一级一片| 丁香花免费高清完整在线播放| 亚洲美女中文字幕| 午夜在线激情影院| 国产精品黄页免费高清在线观看| 日韩欧美中文字幕一区二区三区| 国产原创精品| 国产精品久久久久久久久久10秀 | 国产啪精品视频网站| 99热这里只有精品首页| 国产综合18久久久久久| 999国产精品视频| 青草视频在线观看视频| 美女视频黄 久久| 麻豆精品国产传媒av| 99久久er热在这里只有精品15| 国产精品国产三级国产传播| 好吊成人免视频| 精品人妻一区二区三区换脸明星| 国产香蕉97碰碰久久人人| 久操av在线| 国产日韩欧美在线| 欧美猛男做受videos| 欧美亚洲黄色片| 国产精品一区2区| 影音先锋制服丝袜| 欧美日韩国产精品一区二区三区四区 | 亚洲1区在线| 亚洲五月六月| 久久久久国产精品一区二区| 成人做爰69片免费| 亚洲欧洲综合另类在线 | 欧美麻豆精品久久久久久| 好男人免费精品视频| 91av国产在线| 好吊妞国产欧美日韩免费观看网站| 天天成人综合网| 美女视频一区二区三区| 在线免费看黄视频| 粉嫩老牛aⅴ一区二区三区| 蜜桃av鲁一鲁一鲁一鲁俄罗斯的| 久久成人精品电影| 欧美国产视频| 亚洲综合五月天| 免费欧美日韩国产三级电影| 亚洲黄色小说视频| 在线视频观看一区| 成人免费高清在线播放| 国产成人福利网站| 欧美欧美黄在线二区| 国产亚洲天堂网| 91首页免费视频| 99久热在线精品996热是什么| 欧美精品一区二区久久久| 男女在线观看视频| 国产视频一区二区三区四区| 在线精品一区| 免费黄色三级网站| 精品久久久久久中文字幕| 天天摸天天干天天操| 久久久久免费精品国产| 9l视频自拍蝌蚪9l视频成人| 免费在线观看视频a| 99re8在线精品视频免费播放| 丰满少妇乱子伦精品看片| 精品视频一区在线视频| 三上悠亚亚洲一区| 午夜精品一区二区三区四区| 久久丁香综合五月国产三级网站| 国产精品精品软件男同| 精品少妇一区二区三区日产乱码 | 一区二区三区四区激情| 丰满人妻一区二区三区无码av| 97国产在线观看| 国产欧美日韩一区二区三区四区| www.99在线| 亚洲摸摸操操av| 香蕉视频黄色片| 国产精品美女网站| 欧美一区久久| 国产精品九九视频| 91精品1区2区| 在线电影福利片| 久久国产精品99久久久久久丝袜| 老司机午夜精品视频| 免费黄色激情视频| 亚洲精品成a人在线观看| 欧美xnxx| 亚洲爆乳无码精品aaa片蜜桃| 播五月开心婷婷综合| 波多野结衣视频观看| 欧美成人精品xxx| 亚洲系列另类av| 黄色片免费网址| 岛国av在线不卡| 国产午夜精品久久久久免费视| 国产一区二区高清不卡 | 亚洲男帅同性gay1069| 无码精品一区二区三区在线 |