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

配置屬性熱更新:基于 WatchService 實現(xiàn)方案

開發(fā) 前端
Spring Boot的ConfigurationProperties注解提供了將外部配置綁定到JavaBean的能力,實現(xiàn)了類型安全的配置訪問。它支持分層結構的配置,并提供了屬性校驗等功能,是Spring應用中管理配置的推薦方式。

前言

在現(xiàn)代應用開發(fā)中,配置屬性的動態(tài)更新能力已成為系統(tǒng)靈活性和可維護性的重要指標。傳統(tǒng)的配置方式往往需要重啟應用才能使新配置生效,這在生產(chǎn)環(huán)境中可能造成不必要的服務中斷。

雖然Spring Cloud ConfigApollo這類配置中心能解決問題,但對于中小項目來說太重了——要部署服務,成本太高。

本文將詳細介紹如何結合Java NIOWatchServiceSpringEnvironmentConfigurationProperties 以及ApplicationEvent,構建一套完整的配置屬性熱更新解決方案。

效果圖

圖片圖片

組件解析

WatchService:文件系統(tǒng)監(jiān)聽機制

WatchServiceJava NIO提供的文件系統(tǒng)監(jiān)聽服務,能夠實時監(jiān)測指定目錄或文件的變化,包括創(chuàng)建、修改和刪除等操作。它采用了高效的操作系統(tǒng)原生通知機制,相比傳統(tǒng)的輪詢方式具有更低的資源消耗和更高的響應速度。

try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
    Path path = Paths.get("config");
    path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
    
    while (true) {
        WatchKey key = watchService.poll(1, TimeUnit.SECONDS);
        if (key == null) continue;
        
        for (WatchEvent<?> event : key.pollEvents()) {
            WatchEvent.Kind<?> kind = event.kind();
            if (kind == StandardWatchEventKinds.OVERFLOW) continue;
            
            Path changedFile = (Path) event.context();
            if (changedFile.endsWith("application.properties")) {
                // 處理配置文件變更
                handleConfigChange();
            }
        }
        
        boolean valid = key.reset();
        if (!valid) break;
    }
} catch (Exception e) {
    // 異常處理
}

Environment:配置訪問的核心接口

SpringEnvironment接口是訪問應用配置的集中點,它整合了各種配置源(如.properties文件、系統(tǒng)環(huán)境變量、命令行參數(shù)等),并提供了統(tǒng)一的訪問方式。通過Environment,我們可以獲取到最新的配置屬性值。

@Autowired
private Environment environment;

public String getConfigValue(String key) {
    return environment.getProperty(key);
}

ConfigurationProperties:類型安全的配置綁定

Spring BootConfigurationProperties注解提供了將外部配置綁定到JavaBean的能力,實現(xiàn)了類型安全的配置訪問。它支持分層結構的配置,并提供了屬性校驗等功能,是Spring應用中管理配置的推薦方式。

@ConfigurationProperties(prefix = "app")
@Component
public class AppConfig {
    private String name;
    private int timeout;
    private List<String> allowedOrigins;
    
    // getters and setters
}

ApplicationEvent:配置變更的通知機制

Spring的事件機制允許我們定義和發(fā)布自定義事件,實現(xiàn)組件間的解耦通信。在配置熱更新場景中,我們可以通過發(fā)布配置變更事件,通知系統(tǒng)中依賴該配置的各個組件及時更新狀態(tài)。

// 自定義配置變更事件
public class ConfigChangedEvent extends ApplicationEvent {
    private final String configKey;
    private final String oldValue;
    private final String newValue;
    
    public ConfigChangedEvent(Object source, String configKey, String oldValue, String newValue) {
        super(source);
        this.configKey = configKey;
        this.oldValue = oldValue;
        this.newValue = newValue;
    }
    
    // getters
}

// 發(fā)布事件
@Autowired
private ApplicationEventPublisher publisher;

public void publishConfigChange(String key, String oldValue, String newValue) {
    publisher.publishEvent(new ConfigChangedEvent(this, key, oldValue, newValue));
}

// 監(jiān)聽事件
@Component
public class ConfigChangeListener {
    @EventListener
    public void handleConfigChange(ConfigChangedEvent event) {
        // 處理配置變更
        log.info("Config {} changed from {} to {}", 
                 event.getConfigKey(), 
                 event.getOldValue(), 
                 event.getNewValue());
    }
}

實現(xiàn)方案

結合上述技術組件,我們可以構建一個完整的配置熱更新解決方案,其核心流程如下:

  • 使用WatchService監(jiān)聽配置文件的變化
  • 當配置文件發(fā)生變更時,重新加載配置
  • 更新Environment中的配置值
  • 刷新ConfigurationProperties綁定的Bean
  • 發(fā)布配置變更事件,通知相關組件

配置文件監(jiān)聽服務

首先實現(xiàn)一個配置文件監(jiān)聽服務,使用WatchService監(jiān)測配置文件的變化:

@Component
public class ConfigFileWatcher implements CommandLineRunner, DisposableBean {
    private static final Logger log = LoggerFactory.getLogger(ConfigFileWatcher.class);

    private final WatchService watchService;
    private final Path configPath;
    private final ConfigReloader configReloader;
    private volatile boolean running = true;
    private Thread watchThread;

    public ConfigFileWatcher(ConfigReloader configReloader) throws IOException {
        this.watchService = FileSystems.getDefault().newWatchService();
        this.configPath = Paths.get("D:\\gitee\\self-learn\\01_springboot\\test-demo\\src\\main\\resources");
        this.configReloader = configReloader;

        // 確保配置目錄存在
        if (!configPath.toFile().exists()) {
            boolean created = configPath.toFile().mkdirs();
            if (created) {
                log.info("Created config directory: {}", configPath);
            }
        }

        // 注冊監(jiān)聽事件
        configPath.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
    }

    @Override
    public void run(String... args) {
        watchThread = new Thread(this::watch);
        watchThread.setDaemon(true);
        watchThread.start();
        log.info("Config file watcher started, monitoring: {}", configPath.toAbsolutePath());
    }

    private void watch() {
        while (running) {
            try {
                WatchKey key = watchService.poll(1, TimeUnit.SECONDS);
                if (key == null) continue;

                for (WatchEvent<?> event : key.pollEvents()) {
                    WatchEvent.Kind<?> kind = event.kind();
                    if (kind == StandardWatchEventKinds.OVERFLOW) continue;

                    @SuppressWarnings("unchecked")
                    WatchEvent<Path> pathEvent = (WatchEvent<Path>) event;
                    Path changedFile = pathEvent.context();

                    if (isConfigFile(changedFile.toString())) {
                        log.info("Detected change in config file: {}", changedFile);
                        File file = configPath.resolve(changedFile).toFile();
                        configReloader.reloadConfig(file);
                    }
                }

                boolean valid = key.reset();
                if (!valid) break;
            } catch (Exception e) {
                log.error("Error watching config files", e);
            }
        }
    }

    private boolean isConfigFile(String fileName) {
        return fileName.endsWith(".properties") ||
                fileName.endsWith(".yml") ||
                fileName.endsWith(".yaml");
    }

    @Override
    public void destroy() throws Exception {
        running = false;
        if (watchThread != null) {
            watchThread.join();
        }
        watchService.close();
        log.info("Config file watcher stopped");
    }
}

配置重新加載器

實現(xiàn)配置重新加載器,負責讀取更新后的配置并更新Environment

@Component
public class ConfigReloader {
    private static final Logger log = LoggerFactory.getLogger(ConfigReloader.class);

    private final Environment environment;
    private final ApplicationEventPublisher eventPublisher;
    private final ConfigurableApplicationContext applicationContext;
    private final Map<String, String> currentConfig = new ConcurrentHashMap<>();

    public ConfigReloader(Environment environment,
                          ApplicationEventPublisher eventPublisher,
                          ConfigurableApplicationContext applicationContext) {
        this.environment = environment;
        this.eventPublisher = eventPublisher;
        this.applicationContext = applicationContext;
    }

    @PostConstruct
    public void init() {
        // 初始化當前配置
        loadInitialConfig();
    }

    private void loadInitialConfig() {
        // 從Environment加載初始配置
        if (environment instanceof ConfigurableEnvironment) {
            ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
            for (PropertySource<?> propertySource : env.getPropertySources()) {
                loadPropertySource(propertySource);
            }
        }
    }

    private void loadPropertySource(PropertySource<?> propertySource) {
        try {
            if (propertySource.getSource() instanceof Map) {
                Map<?, ?> sourceMap = (Map<?, ?>) propertySource.getSource();
                sourceMap.forEach((k, v) -> {
                    if (k != null && v != null) {
                        currentConfig.put(k.toString(), v.toString());
                    }
                });
            }
        } catch (Exception e) {
            log.error("Error loading property source: {}", propertySource.getName(), e);
        }
    }

    public void reloadConfig(File configFile) {
        try {
            if (!configFile.exists()) {
                log.warn("Config file not found: {}", configFile.getAbsolutePath());
                return;
            }

            Properties newProperties = loadProperties(configFile);
            if (newProperties == null) {
                return;
            }

            // 比較新舊配置,找出變更項
            Map<String, String> changedProperties = new HashMap<>();

            newProperties.forEach((k, v) -> {
                String key = k.toString();
                String value = v.toString();
                String oldValue = currentConfig.get(key);

                if (!Objects.equals(oldValue, value)) {
                    changedProperties.put(key, value);
                    log.info("Config changed: {} = {}", key, value);
                }
            });

            if (!changedProperties.isEmpty()) {
                // 更新Environment
                updateEnvironment(changedProperties);

                // 刷新ConfigurationProperties
                refreshConfigurationProperties();

                // 發(fā)布配置變更事件
                publishConfigChangeEvents(changedProperties);
            } else {
                log.info("No changes detected in config file: {}", configFile.getName());
            }

        } catch (Exception e) {
            log.error("Error reloading config file: {}", configFile.getAbsolutePath(), e);
        }
    }

    private Properties loadProperties(File configFile) throws IOException {
        if (configFile.getName().endsWith(".yml") || configFile.getName().endsWith(".yaml")) {
            YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
            yamlFactory.setResources(new FileSystemResource(configFile));
            return yamlFactory.getObject();
        } else {
            Properties properties = new Properties();
            try (FileInputStream fis = new FileInputStream(configFile)) {
                properties.load(fis);
            }
            return properties;
        }
    }

    private void updateEnvironment(Map<String, String> changedProperties) {
        if (environment instanceof ConfigurableEnvironment) {
            ConfigurableEnvironment env = (ConfigurableEnvironment) environment;

            // 添加一個新的PropertySource覆蓋舊值
            MapPropertySource newPropertySource = new MapPropertySource(
                    "dynamic-config-" + System.currentTimeMillis(),
                    new HashMap<>(changedProperties)
            );

            env.getPropertySources().addFirst(newPropertySource);
            log.info("Updated environment with {} changed properties", changedProperties.size());
        }
    }

    private void refreshConfigurationProperties() {
        // 獲取所有@ConfigurationProperties Bean并刷新
        Map<String, Object> configBeans = applicationContext.getBeansWithAnnotation(org.springframework.boot.context.properties.ConfigurationProperties.class);
        configBeans.values().forEach(bean -> {
            ConfigurationPropertiesBindingPostProcessor binder =
                    applicationContext.getBean(ConfigurationPropertiesBindingPostProcessor.class);
            try {
                binder.postProcessBeforeInitialization(bean, bean.getClass().getName());
            } catch (Exception e) {
                log.error("Error refreshing configuration bean: {}", bean.getClass().getSimpleName(), e);
            }
        });
        log.info("Refreshed {} configuration properties beans", configBeans.size());
    }

    private void publishConfigChangeEvents(Map<String, String> changedProperties) {
        changedProperties.forEach((key, value) -> {
            String oldValue = currentConfig.get(key);
            eventPublisher.publishEvent(new ConfigChangedEvent(this, key, oldValue, value));
        });
    }

    public String getCurrentConfigValue(String key) {
        return currentConfig.get(key);
    }
}

配置變更事件與監(jiān)聽器

完善配置變更事件和監(jiān)聽器,實現(xiàn)配置變更的通知機制:

public class ConfigChangedEvent extends ApplicationEvent {
    private final String configKey;
    private final String oldValue;
    private final String newValue;

    public ConfigChangedEvent(Object source, String configKey, String oldValue, String newValue) {
        super(source);
        this.configKey = configKey;
        this.oldValue = oldValue;
        this.newValue = newValue;
    }

    public String getConfigKey() {
        return configKey;
    }

    public String getOldValue() {
        return oldValue;
    }

    public String getNewValue() {
        return newValue;
    }
}
@Component
public class ConfigChangeLogger {
    private static final Logger log = LoggerFactory.getLogger(ConfigChangeLogger.class);

    @EventListener
    public void logConfigChange(ConfigChangedEvent event) {
        log.info("Configuration changed - Key: {}, Old Value: {}, New Value: {}",
                event.getConfigKey(),
                event.getOldValue(),
                event.getNewValue());
    }
}
@Component
public class TimeoutConfigListener {
    private static final Logger log = LoggerFactory.getLogger(TimeoutConfigListener.class);
    private int currentTimeout;

    @EventListener
    public void handleTimeoutChange(ConfigChangedEvent event) {
        if ("app.timeout".equals(event.getConfigKey())) {
            try {
                int newTimeout = Integer.parseInt(event.getNewValue());
                currentTimeout = newTimeout;
                log.info("Updating service timeout to {}ms", newTimeout);
                // 這里可以添加實際更新服務超時設置的邏輯
            } catch (NumberFormatException e) {
                log.error("Invalid timeout value: {}", event.getNewValue());
            }
        }
    }

    public int getCurrentTimeout() {
        return currentTimeout;
    }
}

配置屬性 Bean 示例

@Data
@Component
@ConfigurationProperties(prefix = "app")
public class AppConfig {
    private static final Logger log = LoggerFactory.getLogger(AppConfig.class);

    private String name;
    private int timeout = 30;
    private List<String> allowedOrigins = new ArrayList<>();
    private Map<String, String> features = new HashMap<>();

    @PostConstruct
    public void init() {
        log.info("Initializing AppConfig: {}", this);
    }

    @PreDestroy
    public void destroy() {
        log.info("Destroying AppConfig");
    }
}


責任編輯:武曉燕 來源: 一安未來
相關推薦

2024-07-31 08:02:26

Prometheus服務器代碼

2024-04-18 15:22:54

2021-08-03 08:35:36

Vuex數(shù)據(jù)熱更新

2019-11-11 10:38:06

日志配置技術

2025-01-21 11:46:26

2024-07-18 00:05:58

Vite代碼前端

2021-04-15 21:21:59

代碼熱Python函數(shù)

2009-06-14 16:59:16

ibmdwWebSphere

2021-04-19 10:45:52

Webpack熱更新前端

2017-06-16 10:39:51

雙機熱備軟件

2024-05-20 09:07:03

2021-01-20 05:39:50

NacosConfig服務端

2019-09-23 10:51:14

JavaJava虛擬機Linux

2014-09-12 10:30:51

HTML5熱力圖

2021-01-29 10:36:20

Bundle文件Apple

2023-10-12 22:38:18

SpringBoot熱部署

2023-09-11 08:31:12

自動配置熱部署DevTools

2016-09-29 15:44:18

開源上網(wǎng)管理

2023-01-06 09:19:12

Seata分布式事務

2011-04-13 11:33:37

HSRP
點贊
收藏

51CTO技術棧公眾號

91成人福利社区| 日本aaa在线观看| 午夜亚洲福利| 亚洲二区在线播放视频| 国产精品97在线| av在线电影网| 成人免费高清视频在线观看| 欧洲亚洲妇女av| 日韩亚洲欧美中文字幕| 97一区二区国产好的精华液| 日韩欧美aaa| 自拍另类欧美| 日韩精品福利| 国产在线不卡一区| 欧美又大又粗又长| 亚洲一级生活片| 校花撩起jk露出白色内裤国产精品| 欧美视频在线观看一区二区| 丁香六月激情网| av网站无病毒在线| 99久精品国产| 91久久精品www人人做人人爽| 在线视频一区二区三区四区| 亚洲欧美伊人| 色一情一乱一区二区| a级一a一级在线观看| 91麻豆精品国产综合久久久| 色综合网站在线| 91黄色在线看| 国产精品实拍| 国产精品美女久久久久久2018| 国产精品日韩欧美一区二区| ,亚洲人成毛片在线播放| 国产精品亚洲欧美| 久久久久成人精品| 印度午夜性春猛xxx交| 精品国产一区二区三区av片| 精品亚洲一区二区三区四区五区| 中文字幕亚洲日本| 伊人久久大香| 欧美日韩日日夜夜| 国产精品无码一本二本三本色| www.综合| 亚洲高清视频的网址| japanese在线播放| 黄色网在线免费看| 国产精品乱码一区二三区小蝌蚪| 蜜桃麻豆91| 亚洲三区在线播放| av成人免费在线| 国产伦一区二区三区色一情| 国产高清精品软件丝瓜软件| 激情综合色综合久久综合| 国产精品亚洲综合天堂夜夜| 亚洲熟妇无码乱子av电影| 国产精品久久国产愉拍| 91国产中文字幕| 日韩伦理在线视频| 99亚洲一区二区| 97av在线影院| 波多野结衣视频网站| 午夜亚洲性色福利视频| 57pao成人永久免费视频| 日本在线视频中文字幕| 亚洲国产91| 欧美激情精品久久久| 久草视频在线资源站| 黑人一区二区| 91精品成人久久| 亚洲黄色免费观看| 蜜臀av一级做a爰片久久| 国产男人精品视频| 国产黄频在线观看| 99视频精品在线| 日本10禁啪啪无遮挡免费一区二区| 国产三区四区在线观看| 国产精品天天摸av网| 亚洲第一页在线视频| 国产黄a三级三级三级av在线看 | av最新在线| 天天综合网 天天综合色| 免费高清在线观看免费| 91精品国产66| 日韩欧美激情四射| 国产福利短视频| 色爱综合网欧美| 欧美老女人性视频| 国产免费av一区| 久久精品国产成人一区二区三区| 96成人在线视频| 每日更新在线观看av| 国产精品久久久久7777按摩| 99久久久精品视频| 欧洲av一区二区| 欧美一区二区三区不卡| 波多野结衣一本| 婷婷综合伊人| 欧美一级免费看| 国产情侣激情自拍| 91视频91自| 国产麻豆电影在线观看| 欧美13videosex性极品| 欧美女孩性生活视频| 小毛片在线观看| 久久密一区二区三区| 久久久久亚洲精品| 中国精品一区二区| 成人综合婷婷国产精品久久 | 国产在线观看不卡| 天天操天天干天天插| 国产精品国产三级国产| 国产毛片视频网站| 色噜噜成人av在线| 亚洲日韩中文字幕| 日韩激情一区二区三区| 久久99国产精品成人| 久久综合狠狠综合久久综青草| 伦xxxx在线| 日本高清不卡在线观看| japanese在线观看| 欧美永久精品| 国产女同一区二区| 久久久久久女乱国产| 亚洲国产精品精华液网站| 亚洲免费黄色录像| 成人黄色小视频| 欧美最近摘花xxxx摘花| 亚洲国产精品久久人人爱潘金莲 | 欧美日韩偷拍视频| 蜜桃在线一区二区三区| 欧美日韩亚洲免费| 超碰在线cao| 欧美成人一区二区| 疯狂试爱三2浴室激情视频| 日本v片在线高清不卡在线观看| 精品久久久久久亚洲| 污污的网站在线看| 日韩欧美中文一区二区| 国产色无码精品视频国产| 蜜臀av性久久久久蜜臀aⅴ流畅 | 91精品国产91久久久久久密臀 | www日韩欧美| 中日韩在线观看视频| 国产天堂亚洲国产碰碰| 99久久激情视频| 在线日本制服中文欧美| 欧美一区二区三区免费观看| 偷拍精品一区二区三区| 黄色一区二区三区| 91精品国产自产| 欧美一级久久| 日韩精品久久一区二区三区| 久久久一本精品| 亚洲图片欧洲图片av| 亚洲高清视频免费观看| 亚洲国产精品精华液ab| 久久国产这里只有精品| 99久久精品国产亚洲精品 | 欧美激情一区不卡| 黄色三级视频在线| 欧美gay男男猛男无套| 国产综合香蕉五月婷在线| 国产美女福利在线| 日韩午夜激情免费电影| 久久精品国产亚洲av高清色欲| 成人久久18免费网站麻豆| 日韩五码在线观看| 国产欧美日韩在线观看视频| 国产精品流白浆视频| 国产精品一区二区三区视频网站| 日韩三级视频在线看| 日韩精品乱码久久久久久| 久久在线观看免费| 天天干天天操天天玩| 亚洲精品在线观看91| 亚洲精品女av网站| 91在线三级| 国产亚洲欧洲在线| av在线资源观看| 欧美日韩中文字幕综合视频| www.黄色在线| 国产精品一区二区久久不卡 | 开心激情五月网| 国产二区国产一区在线观看| 黄色免费福利视频| 日韩大片在线观看| 粉嫩精品一区二区三区在线观看| 欧美男人天堂| 久久精品国产亚洲| 日本韩国免费观看| 欧美三级欧美一级| 国产一卡二卡在线播放| 国产欧美精品区一区二区三区 | 久久久影视传媒| 色播五月综合网| 国产欧美成人| 欧美 日韩 国产 在线观看| 农村少妇一区二区三区四区五区 | 一区中文字幕电影| 国产成人精品视频| 美女91在线| 中文字幕av一区中文字幕天堂| 国产高清第一页| 欧美亚洲综合网| 成年人免费看毛片| 亚洲色图在线视频| 成人国产精品久久久网站| 懂色av中文一区二区三区| 久久久国产欧美| 国产欧美一区二区色老头| 中文字幕一区二区三区乱码| 要久久爱电视剧全集完整观看| 999视频在线免费观看| 日日av拍夜夜添久久免费| 欧美大成色www永久网站婷| 日韩一二三四| 精品国产免费一区二区三区香蕉| 中文字幕一级片| 欧美日韩中文在线| 日本一区二区三区免费视频| 中文字幕一区av| 国产一区二区三区四区五区六区 | 国产精品高清无码在线观看| 国产精品夜夜爽| 亚洲va综合va国产va中文| 性欧美videos另类喷潮| 国产精品69久久久| 7777久久香蕉成人影院| 亚洲精品高清视频| 色综合中文网| 精品免费视频123区| 91国内精品| ts人妖另类在线| 国产精品日本一区二区三区在线 | 亚洲一级在线播放| 欧美午夜一区二区三区免费大片| 国内精品福利视频| 精品人伦一区二区三区蜜桃网站| 免费无码毛片一区二区app| 亚洲欧洲综合另类在线| 亚洲欧美日韩第一页| 国产亚洲午夜高清国产拍精品| 亚洲av网址在线| 99精品黄色片免费大全| 艳妇乳肉豪妇荡乳xxx| 高清成人在线观看| 图片区偷拍区小说区| 国产成人高清视频| 亚洲美女精品视频| 成人毛片老司机大片| 欧美性生交xxxxx| 国产91在线观看丝袜| 东京热av一区| eeuss鲁片一区二区三区在线观看| 亚洲欧洲国产视频| 不卡一区二区三区四区| 国产精品边吃奶边做爽| 久久综合一区二区| 免费一级做a爰片久久毛片潮| 久久这里只精品最新地址| 国产sm调教视频| 国产精品美女久久福利网站| 国产视频精品免费| 亚洲美女在线国产| 久久网一区二区| 欧美日韩国产一中文字不卡| 亚洲欧美偷拍一区| 欧美日韩一区二区三区不卡| 亚洲自拍第二页| 日韩欧美中文一区| 三级黄视频在线观看| 色老头一区二区三区在线观看| 成人免费看片| 国外成人在线直播| 欧美xxxx做受欧美护士| 成人久久久久久久| 草莓视频一区二区三区| 欧美精品亚洲| 亚洲综合色站| 毛片在线视频播放| 免费观看日韩av| 日本天堂在线播放| 久久丝袜美腿综合| 波多野结衣亚洲一区二区| 亚洲mv大片欧洲mv大片精品| 亚洲大尺度在线观看| 宅男在线国产精品| 五十路在线视频| 自拍视频国产精品| a天堂资源在线| 国产精品爽爽爽爽爽爽在线观看| 欧美电影在线观看一区| 鲁丝一区二区三区免费| 久久久久久久久国产一区| 日本福利视频在线| 久久综合综合久久综合| 久久久久久久无码| 中文字幕一区二区在线观看| 日韩欧美亚洲一区二区三区| 欧美日韩午夜精品| 手机在线不卡av| 少妇高潮久久77777| 两个人看的在线视频www| 成人自拍性视频| 亚洲午夜久久| www.日本在线视频| 蜜桃传媒麻豆第一区在线观看| 男男做爰猛烈叫床爽爽小说| 中文字幕在线视频一区| 特级西西444www大精品视频免费看| 69久久夜色精品国产69蝌蚪网| 深夜福利在线看| 久久91亚洲精品中文字幕| 国产成人免费9x9x人网站视频| 国产麻豆日韩| 欧美激情91| 国产传媒免费观看| 国产亚洲视频系列| 中文字幕一区二区三区精品| 欧美一区二区性放荡片| 国产高清视频免费最新在线| 国内精品免费午夜毛片| 99视频这里有精品| 台湾成人av| 日日夜夜精品视频天天综合网| 亚洲调教欧美在线| 一区二区不卡在线播放| 国产女同91疯狂高潮互磨| 在线精品国产欧美| 精品91久久| 欧美激情视频一区二区三区| 精品二区视频| 在线精品视频播放| 亚洲综合一区二区| 国产成人三级一区二区在线观看一| 中文字幕日韩免费视频| 欧美三级精品| 日本一区免费| 日韩精品一区第一页| 亚洲国产av一区| 色综合一区二区| 精品视频一二三| 日韩av免费在线观看| 亚洲资源网站| 9久久婷婷国产综合精品性色| 国产视频不卡一区| 日韩精品在线一区二区三区| 亚洲视频免费一区| 日本高清不卡一区二区三区视频 | 国产污在线观看| 亚洲一区视频在线| 日本毛片在线观看| 91av视频在线播放| 亚洲小说图片视频| 老司机午夜av| 欧美国产日本视频| 一级特黄aaa大片| 久久夜精品香蕉| 91成人福利| 18禁免费无码无遮挡不卡网站| 久久久久久久综合| 伊人网免费视频| 最近2019中文字幕大全第二页 | 欧美一区二区免费| 欧洲黄色一区| 国产亚洲精品久久飘花| 欧美亚洲视频| 日本伦理一区二区三区| 91精品国产麻豆国产自产在线 | 亚洲一级淫片| 日韩精品一区二区三区高清免费| 欧美日韩国产区| 国产福利在线| 91久久国产婷婷一区二区| 好看的日韩av电影| 一卡二卡三卡四卡| 欧美日韩国产精选| 国内老司机av在线| 欧美日韩国产一二| 国产一区在线观看视频| 日本一区二区三区免费视频| 在线观看91久久久久久| 视频成人永久免费视频| 国产a级一级片| 亚洲欧洲一区二区在线播放| 少妇荡乳情欲办公室456视频| 国产精品第二页| 欧美99在线视频观看| 国产精品300页| 欧美精品vⅰdeose4hd| av中文资源在线资源免费观看| 日韩三级电影网站| 国产白丝网站精品污在线入口| 久久久久久久久久成人| 欧美成人午夜激情| 亚洲伊人春色| 日韩大尺度视频| 欧美影视一区在线| 高潮在线视频| 日本a级片在线观看|