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

一文帶你掌握ApplicationRunner和CommandLineRunner如何使用及實現原理

開發 前端
CommandLineRunner? 和 ApplicationRunner? 常用于應用啟動后的初始化任務或一次性任務執行。它們允許你在 Spring 應用啟動完成后立即執行一些邏輯。

1.概述

ApplicationRunner 和 CommandLineRunner 是 Spring Boot 提供的兩個接口,允許在 Spring 應用程序啟動完成后執行特定的代碼。它們的主要作用是在應用啟動后執行一段初始化或任務邏輯,常見于一些啟動任務,例如加載數據、驗證配置、執行調度等。接下來我們就來詳細看看它們在項目開發中的實際應用

2.實際應用

這兩個擴展點在實際開發中的應用場景挺廣泛的,下面就來看看幾個常見的。

2.1 服務啟動后數據初始化

在應用啟動時加載初始化數據,如將初始數據加載到數據庫、從文件讀取數據、緩存熱點數據等。可以在 CommandLineRunner 或 ApplicationRunner 中執行這些初始化邏輯,確保在應用服務正式對外提供服務之前,必要的數據已經準備好。

這個應用場景我深有感觸,因為這種應用操作可以“去運維化”,尤其對于系統是新安裝或部署而言,它確保應用程序所需的上下文數據無誤,可以立即開始運行,而無需通過手動干預來插入基本數據(PS:環境基礎數據靠運維部署時候去插入總是不可靠的......)。本著天助自助者的原則,我們可以通過CommandLineRunner來完成項目服務環境初始化的工作,這里以平時的后臺管理系統來講述一下,大部分的后臺系統都是基于RBAC模型(Role-Based Access Control:基于角色的訪問控制)進行授權和認證的,這就意味著我們一個全新系統部署之后,會默認插入一個超管賬號,他可以登陸系統訪問所有功能,比如說他可以新增員工,給新員工賦予權限等等,這樣系統就可以用起來了。

@Component
public class DataInitializer implements CommandLineRunner {
    @Resource
    private EnvInitMapper envInitMapper;
    @Resource
    private UserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private UserRoleService userRoleService;
    
    @Override
    public void run(String... args) throws Exception {
        // 1/判斷是不是第一次啟動 若是,執行初始數據插入等操作 若不是,不執行
        // 這個可以讀取數據庫標志,初始化之后插入一個標志記錄即可, 當然也可以讀取緩存
        QueryWrapper<EnvInit>queryWrapper = new QueryWrapper<>();
        EnvInit init = envInitMapper.selectOne(queryWrapper);
        if (Objects.isNull(init)) {
            // 2.第一次初始化環境
            userService.firstInitData();
            // 3.插入已經初始化標志
            init = new EnvInit();
            init.setIsInit(1);
            envInitMapper.insert(init);
        }
    }

    /**
     * 初始化環境基礎數據,可以插入環境所需的任何數據
     */
    @Transactional(rollbackFor = Exception.class)
    public void initData() {
        userService.firstInitData();
        roleService.firstInitData();
        userRoleService.firstInitData();
    }
}

這里我們只是舉例插入了菜單權限所需的基礎數據,你可以根據自身服務環境需求插入所需的任何基礎數據,以保證系統能夠順利正常運行。我們還判斷了是不是第一次初始化基礎數據,防止每次系統服務重啟之后重復插入。

2.2 應用啟動時加載配置信息

在某些情況下,應用可能需要在啟動時加載外部配置信息或數據庫中的參數到內存中進行緩存。

@Component
public class ConfigInitializer implements CommandLineRunner {

    @Override
    public void run(String... args) {
        // 加載配置文件或數據庫配置信息
        System.out.println("加載配置信息...");
        // 例如加載外部配置文件
        // Config config = configService.loadConfig();
    }
}

2.3 啟動時加載數據到緩存

有時你可能希望在應用啟動時將一些常用數據(如字典數據、熱點數據)加載到內存中,以提高訪問效率。

@Component
public class DataCacheInitializer implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) {
        System.out.println("啟動時加載字典數據到緩存...");
        // 假設從數據庫加載數據到緩存
        // List<Dict> dicts = dictService.loadAll();
        // cacheService.cacheDicts(dicts);
    }
}

2.4 啟動時驗證環境配置

之前我們總結過:license版權證書生成與驗證,對license不太熟悉的可自行跳轉查看,簡單概括來說就是,你是軟件服務商,人家買了你的軟件,要求你部署到他們的服務器上,即本地化部署,這時候你就需要打成JAR包去客戶服務器上部署,如果就是簡單的java -jar jar包服務就能啟動跑起來了,那客戶就可以拿著你的jar包去賣了.....license就是為了堵住這個缺口,加了證書驗證,讓你換個環境跑不起來......

@Component
public class LicenseCheckApplicationRunner implements ApplicationRunner {
    @Resource
    private LicenseVerify licenseVerify;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        LicenseContent content = licenseVerify.install();
    }
}
@Component
public class LicenseVerify {
    @Resource
    private LicenseProperties licenseProperties;

    private static Logger logger = LogManager.getLogger(LicenseVerify.class);
    private static final  DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    /**
     * 安裝License證書
     * 項目服務啟動時候安裝證書,檢驗合法性
     * 此時根據開關驗證服務器系統信息
     */
    public synchronized LicenseContent install() {
        LicenseContent result = null;
        try{
            LicenseManager licenseManager = new LicenseManager(initLicenseParam());
            licenseManager.uninstall();
            result = licenseManager.install(new File(licenseProperties.getLicensePath()));
            verifySystemInfo(result);
            logger.info("證書安裝成功,證書有效期:{} - {}", df.format(result.getNotBefore()),
                    df.format(result.getNotAfter()));
        }catch (Exception e){
            logger.error("證書安裝失敗:", e);
            throw new BizException("證書安裝失敗");
        }
        return result;
    }

    /**
     * 校驗License證書, 在接口使用{@link com.plasticene.boot.license.core.anno.License}
     * 時候進入license切面時候調用,此時無需再驗證服務器系統信息,驗證證書和有效期即可
     */
    public boolean verify() {
        try {
            LicenseManager licenseManager = new LicenseManager(initLicenseParam());
            LicenseContent licenseContent = licenseManager.verify();
            verifyExpiry(licenseContent);
            return true;
        }catch (Exception e){
            logger.error("證書校驗失敗:", e);
            throw new BizException("證書檢驗失敗");
        }
    }

    /**
     * 初始化證書生成參數
     */
    private LicenseParam initLicenseParam(){
        Preferences preferences = Preferences.userNodeForPackage(LicenseVerify.class);

        CipherParam cipherParam = new DefaultCipherParam(licenseProperties.getStorePass());

        KeyStoreParam publicStoreParam = new CustomKeyStoreParam(LicenseVerify.class
                ,licenseProperties.getPublicKeysStorePath()
                ,licenseProperties.getPublicAlias()
                ,licenseProperties.getStorePass()
                ,null);

        return new DefaultLicenseParam(licenseProperties.getSubject()
                ,preferences
                ,publicStoreParam
                ,cipherParam);
    }

    // 驗證證書有效期
    private void verifyExpiry(LicenseContent licenseContent) {
        Date expiry = licenseContent.getNotAfter();
        Date current = new Date();
        if (current.after(expiry)) {
            throw new BizException("證書已過期");
        }
    }

    private void verifySystemInfo(LicenseContent licenseContent) {
        if (licenseProperties.getVerifySystemSwitch()) {
            SystemInfo systemInfo = (SystemInfo) licenseContent.getExtra();
            VerifySystemType verifySystemType = licenseProperties.getVerifySystemType();
            switch (verifySystemType) {
                case CPU_ID:
                    checkCpuId(systemInfo.getCpuId());
                    break;
                case SYSTEM_UUID:
                    checkSystemUuid(systemInfo.getUuid());
                    break;
                default:
            }
        }
    }


    private void checkCpuId(String cpuId) {
        cpuId = cpuId.trim().toUpperCase();
        String systemCpuId = DmcUtils.getCpuId().trim().toUpperCase();
        logger.info("配置cpuId = {},  系統cpuId = {}", cpuId, systemCpuId);
        if (!Objects.equals(cpuId, systemCpuId)) {
            throw new BizException("license檢驗cpuId不一致");
        }
    }

    private void checkSystemUuid(String uuid) {
        uuid = uuid.trim().toUpperCase();
        String systemUuid = DmcUtils.getSystemUuid().trim().toUpperCase();
        logger.info("配置uuid = {},  系統uuid= {}", uuid, systemUuid);
        if (!Objects.equals(uuid, systemUuid)) {
            throw new BizException("license檢驗uuid不一致");
        }
    }

}

如果證書校驗不通過,就會拋出異常,項目服務啟動失敗。

2.5 配合 @Order 使用

在同一個 Spring Boot 應用中,可能會有多個 CommandLineRunner 或 ApplicationRunner 實現類。如果你希望控制它們的執行順序,可以使用 @Order 注解,指定多個 Runner 的執行順序。

@Component
@Order(1) // 這個Runner會優先執行
public class FirstRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("FirstRunner running!");
    }
}

@Component
@Order(2) // 這個Runner會后執行
public class SecondRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("SecondRunner running!");
    }
}

當應用啟動時,FirstRunner 會先執行,然后 SecondRunner 執行。

上面的示例都是使用CommandLineRunner,當然換成ApplicationRunner也是可以的。

項目推薦:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企業級系統架構底層框架封裝,解決業務開發時常見的非功能性需求,防止重復造輪子,方便業務快速開發和企業技術??蚣芙y一管理。引入組件化的思想實現高內聚低耦合并且高度可配置化,做到可插拔。嚴格控制包依賴和統一版本管理,做到最少化依賴。注重代碼規范和注釋,非常適合個人學習和企業使用

Github地址:https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址:https://gitee.com/plasticene3/plasticene-boot-starter-parent

微信公眾號:Shepherd進階筆記

交流探討qun:Shepherd_126

3. CommandLineRunner和ApplicationRunner區別

直接看定義:

/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 * <p>
 * If you need access to {@link ApplicationArguments} instead of the raw String array
 * consider using {@link ApplicationRunner}.
 * 如果你需要訪問ApplicationArguments去替換掉字符串數組,可以考慮使用ApplicationRunner類。
 * @author Dave Syer
 * @since 1.0.0
 * @see ApplicationRunner
 */
@FunctionalInterface
public interface CommandLineRunner {

 /**
  * Callback used to run the bean.
  * @param args incoming main method arguments
  * @throws Exception on error
  */
 void run(String... args) throws Exception;

}

ApplicationRunner 和 CommandLineRunner 類似,也是一個在應用啟動后執行的接口。但它更加強大,因為它使用了 ApplicationArguments 對象,而不僅僅是簡單的字符串數組。ApplicationArguments 允許更方便地處理傳入的參數,例如獲取無選項參數和帶選項參數

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner running!");
        for (String arg : args) {
            System.out.println("CommandLineRunner Arg: " + arg);
        }
    }
}

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner running!");
        for (String sourceArg : args.getSourceArgs()) {
            System.out.println("ApplicationRunner Arg: " + sourceArg);
        }
        for (String nonOptionArg : args.getNonOptionArgs()) {
            System.out.println("ApplicationRunner nonOptionArg: " + nonOptionArg);
        }
        for (String optionName : args.getOptionNames()) {
            System.out.println("ApplicationRunner optionArg: " + args.getOptionValues(optionName));
        }


    }
}

在IDEA中配置項目啟動參數:

圖片圖片

啟動服務,控制臺輸出如下:

ApplicationRunner running!
ApplicationRunner Arg: hello
ApplicationRunner Arg: 666
ApplicationRunner Arg: --foo=boo
ApplicationRunner Arg: --foo=eoo
ApplicationRunner Arg: world
ApplicationRunner nonOptionArg: hello
ApplicationRunner nonOptionArg: 666
ApplicationRunner nonOptionArg: world
ApplicationRunner optionArg: [boo, eoo]
CommandLineRunner running!
CommandLineRunner Arg: hello
CommandLineRunner Arg: 666
CommandLineRunner Arg: --foo=boo
CommandLineRunner Arg: --foo=eoo
CommandLineRunner Arg: world

區別如下:

  • 參數處理:

CommandLineRunner 接收一個 String... args,只是簡單地傳遞命令行參數。

ApplicationRunner 使用 ApplicationArguments 對象,它提供了對選項和非選項參數的更強大支持。

  • 用法場景:
  • 如果只是簡單地處理命令行參數或執行一些任務,CommandLineRunner 足夠。

  • 如果你需要更靈活的方式來處理命令行選項和參數,ApplicationRunner 更合適。

  • 參數管理:

  • CommandLineRunner 只能獲得原始的命令行參數。

  • ApplicationRunner 可以通過 ApplicationArguments 方便地獲取命令行選項、非選項參數,并區分它們。

4.實現原理

既然ApplicationRunner和CommandLineRunner是Spring Boot提供的兩個擴展點,我們就來看看項目啟動時它們是怎么執行的。

SpringApplication的核心入口方法#run():

public ConfigurableApplicationContext run(String... args) {
  long startTime = System.nanoTime();
  DefaultBootstrapContext bootstrapContext = createBootstrapContext();
  ConfigurableApplicationContext context = null;
  configureHeadlessProperty();
  SpringApplicationRunListeners listeners = getRunListeners(args);
  listeners.starting(bootstrapContext, this.mainApplicationClass);
  try {
   ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
   ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
   configureIgnoreBeanInfo(environment);
   Banner printedBanner = printBanner(environment);
   context = createApplicationContext();
   context.setApplicationStartup(this.applicationStartup);
   prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
   refreshContext(context);
   afterRefresh(context, applicationArguments);
   Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
   if (this.logStartupInfo) {
    new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
   }
   listeners.started(context, timeTakenToStartup);
      // 執行`ApplicationRunner`和`CommandLineRunner`的方法入庫
   callRunners(context, applicationArguments);
  }
  catch (Throwable ex) {
   handleRunFailure(context, ex, listeners);
   throw new IllegalStateException(ex);
  }
  try {
   Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
   listeners.ready(context, timeTakenToReady);
  }
  catch (Throwable ex) {
   handleRunFailure(context, ex, null);
   throw new IllegalStateException(ex);
  }
  return context;
 }

#callRunners(context, applicationArguments),從方法名就知道實現ApplicationRunner和CommandLineRunner的核心所在咯。

private void callRunners(ApplicationContext context, ApplicationArguments args) {
  List<Object> runners = new ArrayList<>();
    // 從spring容器中獲取ApplicationRunner類型的bean放入到集合runners中
  runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    // 從spring容器中獲取CommandLineRunner類型的bean放入到集合runners中
  runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    // 排序
  AnnotationAwareOrderComparator.sort(runners);
  for (Object runner : new LinkedHashSet<>(runners)) {
   if (runner instanceof ApplicationRunner) {
    callRunner((ApplicationRunner) runner, args);
   }
   if (runner instanceof CommandLineRunner) {
    callRunner((CommandLineRunner) runner, args);
   }
  }
 }

最后通過#callRunner()執行run方法

private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
  try {
   (runner).run(args);
  }
  catch (Exception ex) {
   throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
  }
 }

5.總結

CommandLineRunner 和 ApplicationRunner 常用于應用啟動后的初始化任務或一次性任務執行。它們允許你在 Spring 應用啟動完成后立即執行一些邏輯。ApplicationRunner 更適合需要處理命令行參數的場景,而 CommandLineRunner 更簡單直接。通過 @Order 注解可以控制多個 Runner 的執行順序,確保初始化操作按特定順序進行。

本文轉載自微信公眾號「Shepherd進階筆記」,可以通過以下二維碼關注。轉載本文請聯系公眾號。

責任編輯:武曉燕 來源: Shepherd進階筆記
相關推薦

2022-12-20 07:39:46

2023-12-21 17:11:21

Containerd管理工具命令行

2021-09-02 12:07:48

Swift 監聽系統Promise

2023-12-15 09:45:21

阻塞接口

2021-02-22 09:05:59

Linux字符設備架構

2021-06-04 09:35:05

Linux字符設備架構

2020-12-18 11:54:22

Linux系統架構

2023-04-04 08:01:47

2022-08-03 08:01:16

CDN網站服務器

2020-03-18 13:40:03

Spring事數據庫代碼

2023-11-20 08:18:49

Netty服務器

2022-10-21 17:24:34

契約測試定位

2023-09-11 06:32:30

VPAHPA容量

2021-04-28 08:05:30

SpringCloudEureka服務注冊

2023-07-31 08:18:50

Docker參數容器

2021-05-29 10:11:00

Kafa數據業務

2022-11-11 19:09:13

架構

2023-11-06 08:16:19

APM系統運維

2023-03-31 08:16:53

Flutter優化內存管理

2023-12-26 08:08:02

Spring事務MySQL
點贊
收藏

51CTO技術棧公眾號

亚洲天堂成人av| 国产性生活免费视频| 91porny九色| 国产高清一区| 亚洲а∨天堂久久精品9966| 无码人妻丰满熟妇区毛片18| 精品麻豆一区二区三区| 懂色一区二区三区免费观看 | 蜜桃传媒视频麻豆一区| 国产女优在线播放| 在线精品在线| 深夜福利亚洲导航| 成人午夜精品无码区| 久久精品女人天堂av免费观看 | 国产98色在线|日韩| 日韩av观看网址| 加勒比av在线播放| 欧美色图激情小说| 亚洲国产精品va在线| mm131亚洲精品| 中文字幕21页在线看| 玉米视频成人免费看| 午夜精品区一区二区三| 五月婷婷六月丁香综合| 国产在线精品视频| 国产精品久久久久久av下载红粉 | 欧美日韩中文字幕一区| 国产a级片网站| 免费不卡视频| 久久久久久综合| 国产精品大全| 国产精品一级视频| 日韩一区欧美二区| 57pao国产成人免费| 18精品爽视频在线观看| 天天综合一区| 中文字幕在线精品| 国产小视频自拍| 国产成人一二| 精品免费一区二区三区| 天天色天天干天天色| 欧美极品在线| 欧美日韩一区久久| 欧美日韩亚洲自拍| 午夜日韩成人影院| 日韩欧美亚洲范冰冰与中字| 日本韩国欧美在线观看| av蜜臀在线| 亚洲大片一区二区三区| 久操手机在线视频| 在线观看中文字幕的网站| 日韩毛片一二三区| 潘金莲一级淫片aaaaa免费看| 色三级在线观看| 国产精品九色蝌蚪自拍| 亚洲精品在线免费| 暖暖日本在线观看| 亚洲色图都市小说| 好吊色视频988gao在线观看| 中文字幕在线观看网站| 一区二区三区在线免费视频| 今天免费高清在线观看国语| bestiality新另类大全| 一级特黄大欧美久久久| 妞干网在线视频观看| www.亚洲成人网| 亚洲日本中文字幕在线| www激情久久| 日本不卡高清视频一区| www.成人.com| 中文字幕在线不卡视频| 免费观看国产视频在线| 欧美人与禽性xxxxx杂性| 亚洲成人av免费| 播放灌醉水嫩大学生国内精品| 亚洲精品一区| 欧美人狂配大交3d怪物一区| 亚洲天堂网站在线| 久久精品论坛| 亚洲香蕉伊综合在人在线视看 | 亚洲黄色小说网| 成人福利视频在线| 欧美日韩国产免费一区二区三区| 爱久久·www| 亚洲男人的天堂av| 黄色www网站| 99久久er| 日韩欧美123| 女尊高h男高潮呻吟| 色综合咪咪久久网| 国内精品久久久| 国产91av在线播放| 从欧美一区二区三区| 久久riav二区三区| 精精国产xxxx视频在线| 午夜不卡在线视频| 中文字幕成人在线视频| 国产厕拍一区| 神马国产精品影院av| www青青草原| 久久一二三区| 亚洲已满18点击进入在线看片| 天天色综合久久| 国产精品女主播av| 精品久久久久久无码中文野结衣| 日本精品不卡| 日韩欧美色综合| 日韩在线免费观看av| 欧美在线免费| 国产精品女主播视频| 人妻与黑人一区二区三区| 国产精品久久99| 最近2019中文免费高清视频观看www99| 久草热视频在线观看| 成人日韩在线观看| 亚洲大胆美女视频| 国产精品视频一区二区三 | 日韩影视在线观看| 久久精品成人动漫| 五月天婷婷导航| 成人深夜在线观看| 中文字幕在线观看一区二区三区| 成人影院大全| 亚洲成人久久一区| 天天做夜夜爱爱爱| 久久久久久色| 国产自产精品| 国产一区久久精品| 在线免费观看视频一区| 岛国精品资源网站| 激情综合自拍| 国产66精品久久久久999小说 | 欧美日韩高清区| 中文字幕欧美人妻精品一区蜜臀| 99久久综合色| 国产高清www| 久久九九精品视频| 日韩中文字幕精品| 免费看一级视频| 99精品黄色片免费大全| 福利视频一区二区三区四区| 国产日本亚洲| 亚洲精品中文字| 中文字幕第四页| 91在线观看下载| 无码播放一区二区三区| 成人av激情人伦小说| 欧美大片免费看| 亚洲av无码国产精品永久一区| 亚洲欧美aⅴ...| 在线免费黄色小视频| 亚洲精品国产首次亮相| 成人精品视频99在线观看免费| 免费a级毛片在线播放| 欧美日韩国产精品自在自线| 久久久国产一级片| 激情五月婷婷综合| 今天免费高清在线观看国语| 日韩精品三级| 国模私拍视频一区| 久草视频视频在线播放| 91成人在线精品| 中国1级黄色片| 国产麻豆精品一区二区| 久艹在线免费观看| 亚洲国产最新| 国产精品久久久久久久久免费| 国产免费a∨片在线观看不卡| 91黄色免费版| 亚洲精品天堂网| 国产一区视频网站| 亚洲 欧美 日韩 国产综合 在线| 亚洲盗摄视频| 国产精品久久激情| 日本在线www| 精品三级在线看| 国产免费一区二区三区四区五区| 国产精品三级电影| 免费看91视频| 久久青草久久| 熟女视频一区二区三区| 精品国产午夜肉伦伦影院| 青青草国产精品一区二区| 在线国产91| 亚洲大胆人体在线| 无码久久精品国产亚洲av影片| 亚洲精品中文字幕乱码三区| 色婷婷免费视频| 另类小说一区二区三区| 91成人综合网| 色小子综合网| 久久久久无码国产精品一区| 久久亚洲精品中文字幕| 久久久久久久久久久久久久久久久久av| 四虎影视在线播放| 欧美喷水一区二区| 欧美亚韩一区二区三区| 国产精品麻豆欧美日韩ww| 国产亚洲精品成人a| 日欧美一区二区| av 日韩 人妻 黑人 综合 无码| 嫩草国产精品入口| 91精品国产综合久久久久久久久 | 国产91在线播放精品91| 黄色精品免费看| 亚洲欧美日韩中文在线| 国内精品久久久久久久久久久| 一本一本久久a久久精品综合麻豆| 欧产日产国产v| 中文字幕二三区不卡| 亚洲中文字幕无码一区| 精品无人码麻豆乱码1区2区 | 欧美另类videos| 免费欧美一区| 国产精品有限公司| 99精品视频在线免费播放| 日本成人黄色片| 福利小视频在线| 日韩有码在线电影| 欧美日韩影视| 亚洲国产三级网| 国产xxxxxx| 欧美另类一区二区三区| 无码人妻精品一区二区三区蜜桃91 | 精品国产乱码一区二区三区四区| h1515四虎成人| 国产不卡精品视男人的天堂| а√在线天堂官网| 欧美日韩xxxxx| 国产在线观看免费麻豆| 中文字幕亚洲综合久久筱田步美| 欧美新色视频| 亚洲精品美女久久| 日韩一级中文字幕| 精品日本一线二线三线不卡 | 亚洲精品影视在线观看| 男人的天堂a在线| 日韩久久精品一区| 精品久久久免费视频| 91精品婷婷国产综合久久性色| 伊人久久成人网| 欧美日韩成人综合天天影院 | 麻豆免费精品视频| 9l视频白拍9色9l视频| 日韩成人精品视频| 在线观看免费黄网站| 天堂影院一区二区| 欧美精品一区二区三区免费播放| 久久亚洲精选| 免费看a级黄色片| 奇米色777欧美一区二区| 美女喷白浆视频| 奇米777欧美一区二区| 午夜免费福利视频在线观看| 另类专区欧美蜜桃臀第一页| 99日在线视频| 国产成人自拍网| 亚洲v在线观看| av综合在线播放| 30一40一50老女人毛片| 国产香蕉久久精品综合网| 一区二区三区在线观看免费视频| 国产精品私房写真福利视频| 三级黄色免费观看| 亚洲黄色av一区| 久草手机在线观看| 欧美中文字幕亚洲一区二区va在线| 中文字幕有码视频| 欧美一级夜夜爽| 污污视频在线免费看| 亚洲精品一区av在线播放| yes4444视频在线观看| 久久久999国产| av2020不卡| 国产成人午夜视频网址| 只有精品亚洲| 国产精品一区视频网站| 激情综合网五月| 超碰97在线看| 亚洲欧美日本日韩| 欧美日韩一区二区三区69堂| 国产成人在线电影| 朝桐光av一区二区三区| 国产精品久久久久一区| 黄色激情视频在线观看| 欧洲av在线精品| 亚洲av无码乱码国产精品久久| 亚洲精品久久视频| 老司机福利在线视频| 久久久免费观看视频| www.久久| 国产chinese精品一区二区| 国产不卡av一区二区| 九一免费在线观看| 日韩综合一区二区| ass极品水嫩小美女ass| 久久只精品国产| 久久久久久久久久久久久久久久久| 精品久久久久久久久久久| 中文字幕精品无码亚| 亚洲电影免费观看| 日本在线观看| 国产成人精品视频在线| 日韩一区二区三区精品| 午夜免费电影一区在线观看| 激情久久五月| 欧美一级xxxx| 久久精品男人的天堂| 免费一级a毛片夜夜看| 欧美日韩另类一区| 日韩av资源| 久久久噜噜噜久久久| 粉嫩一区二区三区在线观看 | 一个色综合网| 蜜臀久久99精品久久久酒店新书| 国产mv日韩mv欧美| 中文字幕乱码av| 日本韩国视频一区二区| 人妻无码一区二区三区久久99| 久久久电影免费观看完整版| 国产精品毛片久久久久久久久久99999999| 国产精品一区二区三区观看| 久久精品一区二区不卡| 久久久国产欧美| 久久婷婷综合激情| 久久夜色精品亚洲| 精品国产乱子伦一区| 成人在线网址| 91九色蝌蚪国产| 日韩在线综合| 久久午夜夜伦鲁鲁一区二区| 91在线porny国产在线看| 国产精品7777| 精品国产乱码久久久久久久| 在线中文字幕视频观看| 91在线观看免费| 亚洲中无吗在线| www.污污视频| 亚洲同性gay激情无套| 91亚洲国产成人久久精品麻豆| 在线观看欧美日韩| 成人福利片在线| 一区二区日本| 久久99精品久久久久| www.com.av| 91精品黄色片免费大全| 蜜桃视频网站在线| 91亚洲一区精品| 欧美精品播放| 亚洲色偷偷色噜噜狠狠99网| 亚洲电影第三页| 神马午夜在线观看| 2020欧美日韩在线视频| 九九视频精品全部免费播放| 最近免费中文字幕中文高清百度| ww亚洲ww在线观看国产| 国产乱码77777777| 色爱av美腿丝袜综合粉嫩av| 国产成人午夜性a一级毛片| 在线免费观看成人网| 国产揄拍国内精品对白| 久久高清无码视频| 日韩成人激情视频| 东京一区二区| 亚洲巨乳在线观看| 国产自产v一区二区三区c| 欧美人与禽zozzo禽性配| 亚洲成人精品久久| 浪潮色综合久久天堂| 亚洲一二三区精品| 国产精品一区二区在线播放 | 欧美午夜精品久久久久久孕妇| 97在线观看免费观看高清| 91九色单男在线观看| 欧美日韩免费| 国产美女精品久久| 欧美日韩一区在线| 国产盗摄一区二区| 欧美日韩国产精品一区二区| 蜜臀国产一区二区三区在线播放 | 黄网站在线观看| 成人精品在线观看| 妖精视频成人观看www| 在线看片中文字幕| 日韩欧美区一区二| 久久青青视频| 激情五月五月婷婷| 久久影院午夜论| 国产精品毛片久久久久久久av| 久久久之久亚州精品露出| 国产91久久精品一区二区| 日本高清免费在线视频| 精品久久久香蕉免费精品视频| 欧美尤物美女在线| 精品久久中出| 国产在线一区二区综合免费视频| 精品91久久久| 久久久精品在线观看| 偷窥自拍亚洲色图精选| 天天干天天曰天天操|