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

Spring Framework&Spring Boot集成apollo源碼分析

開發(fā) 架構
ApolloConfigRegistrar最終將apollo中BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor、BeanPostProcessor實現(xiàn)類的注冊到spring容器中(具體實現(xiàn)類與Spring Framework部分基本是一致的),后續(xù)的邏輯與Spring Framework部分分析的是一致的了。

引言

為了在項目中用好框架,以及出現(xiàn)問題時候能夠快速定位、分析、優(yōu)化,文章嘗試從源碼角度分析Spring集成apollo的過程。期望文章能夠把以下幾個事情描述清楚:

  • apollo通過使用Spring哪些擴展點,完成了與Spring的集成;
  • apollo中的配置如何融入到Spring Environment;
  • apollo中的配置項如何賦值給Spring Bean相關字段、方法;
  • 在應用運行過程中,當修改apollo中的配置,配置如何在Spring Bean相關字段、方法上生效的

由于Spring Framework和Spring Boot集成apollo的方式有些許不同,分別進行分析。

Spring Framework

示例

Spring XML配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:apollo="http://www.ctrip.com/schema/apollo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.ctrip.com/schema/apollo
http://www.ctrip.com/schema/apollo.xsd"
>
<apollo:config namespaces="application,public_namespace"/>
<context:component-scan base-package="test.springframework"/>

<bean id="test" class="test.springframework.Test">
<property name="test1" value="${test1}"/>
</bean>
</beans>
  • apollo:config配置的是apollo app.id中的命令空間(app.id、app.meta配置可以參考apollo官方文檔);
  • context:component-scan配置的是Spring component注解的掃描路徑;
  • 另一個重要的配置是xmlns:apollo="http://www.ctrip.com/schema/apollo",后面內容會有分析。

Spring Bean

package test.springframework;
public class Test {
@ApolloConfig
private Config config;
@Value("${test2:}")
private String test2;
private String test1;
public String getTest1(){
return test1;
}
public void setTest1(String test1){
this.test1 = test1;
}
@ApolloConfigChangeListener
public void onChange(ConfigChangeEvent changeEvent){
System.out.println(changeEvent);
}
}

集成分析

refresh時序圖

圖中概括地描述了refresh過程,其中標識黃顏色的地方是這次分析的重點,下面分別進行描述。

解析apollo:config

當解析xml文件apollo:config標記的時候調用BeanDefinitionParserDelegate.parseCustomElement(…),主要流程如下:

個性化命名空間解析

圖中流程主要完成了兩件事:

  • 將xml中配置的apollo命名空間存儲到了PropertySourcesProcessor(屬于apollo jar包)類中的NAMESPACE_NAMES字段;
  • 將ConfigPropertySourcesProcessor(屬于apollo jar包)作為BeanDefinition注冊到了Spring容器中;ConfigPropertySourcesProcessor實現(xiàn)了Spring接口BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor。

調用BeanFactoryPostProcessor

apollo中ConfigPropertySourcesProcessor實現(xiàn)了Spring接口BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor,ConfigPropertySourcesProcessor實現(xiàn)如下:

public class ConfigPropertySourcesProcessor extends PropertySourcesProcessor
implements BeanDefinitionRegistryPostProcessor {
//使用java SPI機制,ConfigPropertySourcesProcessorHelper對應的實現(xiàn)類是DefaultConfigPropertySourcesProcessorHelper,這段代碼完成了apollo client初始化
private ConfigPropertySourcesProcessorHelper helper = ServiceBootstrap.loadPrimary(ConfigPropertySourcesProcessorHelper.class);

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
helper.postProcessBeanDefinitionRegistry(registry);
}
}

調用BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry

實際調用的是
DefaultConfigPropertySourcesProcessorHelper.postProcessBeanDefinitionRegistry方法,該方法主要完成以下幾件事:

  • 將PropertySourcesPlaceholderConfigurer注冊到spring容器中,該類實現(xiàn)了接口BeanFactoryPostProcessor,用于占位符的轉換處理;
  • 將ApolloAnnotationProcessor注冊到spring容器中,該類實現(xiàn)了接口BeanPostProcessor;
  • 將SpringValueProcessor注冊到spring容器中,該類實現(xiàn)了接口BeanFactoryPostProcessor和BeanPostProcessor;
  • 將ApolloJsonValueProcessor注冊到spring容器中,該類實現(xiàn)了接口BeanPostProcessor;
  • 將BeanDefinition中帶有占位符的所有屬性存儲到Map<BeanDefinitionRegistry, ?Multimap<String, SpringValueDefinition>>結構中

調用BeanFactoryPostProcessor.postProcessBeanFactory

PropertySourcesProcessor

CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME);
ImmutableSortedSet<Integer> orders = ImmutableSortedSet.copyOf(NAMESPACE_NAMES.keySet());
Iterator<Integer> iterator = orders.iterator();

while (iterator.hasNext()) {
int order = iterator.next();
for (String namespace : NAMESPACE_NAMES.get(order)) {
Config config = ConfigService.getConfig(namespace);
composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
}
}
NAMESPACE_NAMES.clear();
environment.getPropertySources().addFirst(composite);
  • NAMESPACE_NAMES中存儲的是應用配置的apollo命名空間;
  • 通過Config config = ConfigService.getConfig(namespace)獲取每個命名空間的配置對象,將Config對象封裝成ConfigPropertySource,接著將所有ConfigPropertySource放入CompositePropertySource,最后將CompositePropertySource加入到spring ConfigurableEnvironment中,此時spring容器的ConfigurableEnvironment已經(jīng)擁有了apollo命令空間的配置;
AutoUpdateConfigChangeListener autoUpdateConfigChangeListener = new AutoUpdateConfigChangeListener(environment, beanFactory);

List<ConfigPropertySource> configPropertySources = configPropertySourceFactory.getAllConfigPropertySources();
for (ConfigPropertySource configPropertySource : configPropertySources) {
configPropertySource.addChangeListener(autoUpdateConfigChangeListener);
}
  • 為apollo命名空間對象添加監(jiān)聽AutoUpdateConfigChangeListener,當改變命名空間中配置的時候,該監(jiān)聽完成Bean對象屬性值得更新,及方法的調用。

PropertySourcesPlaceholderConfigurer

  • 將ConfigurableEnvironment構造成自身的PropertySource;
new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
public String getProperty(String key) {
return this.source.getProperty(key);
}
}
  • 通過自身的PropertySource構造PropertySourcesPropertyResolver,PropertySourcesPropertyResolver中完成解析的類是PropertyPlaceholderHelper;
new PropertySourcesPropertyResolver(this.propertySources)
  • 構造StringValueResolver,然后調用PropertySourcesPropertyResolver來進行解析;
StringValueResolver valueResolver = strVal -> {
String resolved = (ignoreUnresolvablePlaceholders ?
propertyResolver.resolvePlaceholders(strVal) :
propertyResolver.resolveRequiredPlaceholders(strVal));
if (trimValues) {
resolved = resolved.trim();
}
return (resolved.equals(nullValue) ? null : resolved);
};
  • 構造BeanDefinitionVisitor,用于解析BeanDefinition包含的所有String值(屬性、構造方法參數(shù)、元數(shù)據(jù)),解析找到的任何占位符。
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);

public void visitBeanDefinition(BeanDefinition beanDefinition) {
visitParentName(beanDefinition);
visitBeanClassName(beanDefinition);
visitFactoryBeanName(beanDefinition);
visitFactoryMethodName(beanDefinition);
visitScope(beanDefinition);
if (beanDefinition.hasPropertyValues()) {
visitPropertyValues(beanDefinition.getPropertyValues());
}
if (beanDefinition.hasConstructorArgumentValues()) {
ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
visitIndexedArgumentValues(cas.getIndexedArgumentValues());
visitGenericArgumentValues(cas.getGenericArgumentValues());
}
}

@Nullable
protected String resolveStringValue(String strVal) {
if (this.valueResolver == null) {
throw new IllegalStateException("No StringValueResolver specified - xxx");
}
// 最終調用的是PropertySourcesPropertyResolver中的resolveXXX方法String resolvedValue = this.valueResolver.resolveStringValue(strVal);
return (strVal.equals(resolvedValue) ? strVal : resolvedValue);
}

調用BeanPostProcessor

ApolloAnnotationProcessor

用于解析apollo注解ApolloConfig、
ApolloConfigChangeListener。

ApolloConfig

為注解為ApolloConfig的字段賦值對應的namespace Config對象。

protected void processField(Object bean, String beanName, Field field) {
ApolloConfig annotation = AnnotationUtils.getAnnotation(field, ApolloConfig.class);
if (annotation == null) {
return;
}

Preconditions.checkArgument(Config.class.isAssignableFrom(field.getType()),
"Invalid type: %s for field: %s, should be Config", field.getType(), field);

String namespace = annotation.value();
Config config = ConfigService.getConfig(namespace);

ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, bean, config);
}

ApolloConfigChangeListener

為注解為ApolloConfigChangeListener的方法添加namespace的監(jiān)聽。

ApolloConfigChangeListener annotation = AnnotationUtils
.findAnnotation(method, ApolloConfigChangeListener.class);
String[] namespaces = annotation.value();
ConfigChangeListener configChangeListener = new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
ReflectionUtils.invokeMethod(method, bean, changeEvent);
}
};
for (String namespace : namespaces) {
Config config = ConfigService.getConfig(namespace);
config.addChangeListener(configChangeListener);
}

SpringValueProcessor

  • 將Bean中含有Value注解的字段、方法注冊到SpringValueRegistry(Map<BeanFactory, Multimap<String, SpringValue>>)中,SpringValue保存了Bean實例,對應的key,F(xiàn)ield或Method;
protected void processField(Object bean, String beanName, Field field) {
Value value = field.getAnnotation(Value.class);
Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());
for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false);
springValueRegistry.register(beanFactory, key, springValue);
}
}
protected void processMethod(Object bean, String beanName, Method method) {
Value value = method.getAnnotation(Value.class);
Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());
for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);
springValueRegistry.register(beanFactory, key, springValue);
}
}
  • 將DefaultConfigPropertySourcesProcessorHelper中解析的Map<BeanDefinitionRegistry, Multimap<String, SpringValueDefinition>>轉換為SpringValue保存在SpringValueRegistry中;
  • 前面在PropertySourcesProcessor類中對每個namespace Config對象注冊了監(jiān)聽AutoUpdateConfigChangeListener,AutoUpdateConfigChangeListener類含有SpringValueRegistry的引用;
  • 當namespace Config配置改變的時候會通知到AutoUpdateConfigChangeListener,AutoUpdateConfigChangeListener通過配置key找到對應的SpringValue對象,通過SpringValue改變Bean對應的屬性,或調用Bean對應的方法。

ApolloJsonValueProcessor

  • 將Bean中含有ApolloJsonValue注解的字段、方法注冊到SpringValueRegistry(Map<BeanFactory, Multimap<String, SpringValue>>)中,SpringValue保存了Bean實例,對應的key,F(xiàn)ield或Method;
  • 對于注解在Field的情況,獲取ApolloJsonValue key的配置,將配置轉換為Field對應類型的對象并完成對Field的賦值;
protected void processField(Object bean, String beanName, Field field) {
ApolloJsonValue apolloJsonValue = AnnotationUtils.getAnnotation(field, ApolloJsonValue.class);
String placeholder = apolloJsonValue.value();
Object propertyValue = placeholderHelper
.resolvePropertyValue(beanFactory, beanName, placeholder);
boolean accessible = field.isAccessible();
field.setAccessible(true);
ReflectionUtils
.setField(field, bean, parseJsonValue((String)propertyValue, field.getGenericType()));
field.setAccessible(accessible);
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder);
for (String key : keys) {
SpringValue springValue = new SpringValue(key, placeholder, bean, beanName, field, true);
springValueRegistry.register(beanFactory, key, springValue);
}
}
}
  • 對于注解在Method的情況,獲取ApolloJsonValue key的配置,將配置轉換為Method入?yún)愋偷膶ο蟛⑼瓿蓪ethod的調用
protected void processMethod(Object bean, String beanName, Method method) {
ApolloJsonValue apolloJsonValue = AnnotationUtils.getAnnotation(method, ApolloJsonValue.class);
String placeHolder = apolloJsonValue.value();
Object propertyValue = placeholderHelper
.resolvePropertyValue(beanFactory, beanName, placeHolder);
boolean accessible = method.isAccessible();
method.setAccessible(true);
ReflectionUtils.invokeMethod(method, bean, parseJsonValue((String)propertyValue, types[0]));
method.setAccessible(accessible);

if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeHolder);
for (String key : keys) {
SpringValue springValue = new SpringValue(key, apolloJsonValue.value(), bean, beanName,method, true);
springValueRegistry.register(beanFactory, key, springValue);
}
}
}

Spring Boot

示例

// Spring Boot啟動類
@SpringBootApplication
@EnableApolloConfig
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
//測試Bean見Spring Framework部分示例

上面代碼中的@EnableApolloConfig是一個接入點,后面會分析到。

集成分析

Spring Boot啟動流程

圖中概括地描述了SpringApplication啟動過程(其中會將啟動類加入到spring容器中),其中標識黃顏色的地方是這次分析的重點,下面分別進行描述。

加載apollo ApplicationContextInitializer

  • 通過SpringFactoriesLoader加載apollo jar包中META-INF/spring.factories文件,解析ApplicationContextInitializer實現(xiàn)類ApolloApplicationContextInitializer。
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 通過SpringFactoriesLoader加載、解析META-INF/spring.factories
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

apollo ApplicationContextInitializer initialize

  • ApolloApplicationContextInitializer解析apollo.bootstrap.namespaces配置的命名空間名稱,然后通過Config config = ConfigService.getConfig(namespace)獲取每個命名空間的配置對象,將Config對象封裝成ConfigPropertySource,接著將所有ConfigPropertySource放入CompositePropertySource,最后將CompositePropertySource加入到spring ConfigurableEnvironment中,此時spring容器的ConfigurableEnvironment已經(jīng)擁有了apollo命令空間的配置。
protected void initialize(ConfigurableEnvironment environment) {
String namespaces = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, ConfigConsts.NAMESPACE_APPLICATION);
List<String> namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);

CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
for (String namespace : namespaceList) {
Config config = ConfigService.getConfig(namespace);

composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
}

environment.getPropertySources().addFirst(composite);
}

初始化BeanDefinitionLoader

我們關注BeanDefinitionLoader類中屬性annotatedReader=new
AnnotatedBeanDefinitionReader(registry),AnnotatedBeanDefinitionReader構造方法如下:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
// 將Annotation相關的處理類注冊到Spring容器中,如:// ConfigurationClassPostProcessor : 處理Configuration注解// AutowiredAnnotationBeanPostProcessor : 處理Value注解// RequiredAnnotationBeanPostProcessor : 處理Required注解// CommonAnnotationBeanPostProcessor : 處理PostConstruct/PreDestroy/Resource/Lazy注解// ... ...
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

與我們這次分析相關的類是:
ConfigurationClassPostProcessor,該類實現(xiàn)了BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor接口。

ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry

  • 判斷spring容器中BeanDefinition是否含有Configuration、Component、ComponentScan、Import

ImportResource、Bean注解,沒有則直接返回;

  • 構造ConfigurationClassParser(Parses a Configuration class definition, populating a collection of ConfigurationClass objects (parsing a single Configuration class may result in any number of ConfigurationClass objects because one Configuration class may import another using the Import annotation)),接著對BeanDefinition上的Configuration、Component、ComponentScan、Import

ImportResource、Bean注解進行解析。

  • 解析完成后,通過ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClass)進行apollo相關BeanDefinition的加載:apollo EnableApolloConfig注解的定義如下
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
// 在上面parse階段會將Import封裝在ConfigurationClass中
@Import(ApolloConfigRegistrar.class)
public @interface EnableApolloConfig {
String[] value() default {ConfigConsts.NAMESPACE_APPLICATION};
int order() default Ordered.LOWEST_PRECEDENCE;
}
  • ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars會調用到ApolloConfigRegistrar類的registerBeanDefinitions方法
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata)
registrar.registerBeanDefinitions(metadata, this.registry));
}
  • ApolloConfigRegistrar最終將apollo中BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor、BeanPostProcessor實現(xiàn)類的注冊到spring容器中(具體實現(xiàn)類與Spring Framework部分基本是一致的),后續(xù)的邏輯與Spring Framework部分分析的是一致的了。
public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar {

private ApolloConfigRegistrarHelper helper = ServiceBootstrap.loadPrimary(ApolloConfigRegistrarHelper.class);

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
// 該方法中將apollo相關類注冊到spring容器中,如:// PropertySourcesProcessor// ApolloAnnotationProcessor// SpringValueProcessor// SpringValueDefinitionProcessor// ApolloJsonValueProcessor
helper.registerBeanDefinitions(importingClassMetadata, registry);
}
}

總結

?文章主要介紹了apollo借助Spring擴展點完成了與Spring的集成:Spring Framework集成方式使用到了loadBeanDefinitions階段中apollo:config NamespaceHandler,BeanDefinitionRegistryPostProcessor,BeanFactoryPostProcessor,BeanPostProcessor;Spring Boot集成方式使用到了ApplicationContextInitializer,BeanDefinitionRegistryPostProcessor,BeanFactoryPostProcessor,BeanPostProcessor;

apollo還提供了通過注解類ApolloAutoConfiguration與Spring Boot完成集成,原理是一致的。

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2009-06-22 11:54:28

Spring MVCSpringframe

2023-06-02 16:24:46

SpringBootSSM

2018-11-02 15:45:41

Spring BootRedis數(shù)據(jù)庫

2020-07-14 11:00:12

Spring BootRedisJava

2019-12-03 11:00:08

spring bootspring-kafkJava

2020-09-02 17:28:26

Spring Boot Redis集成

2009-06-18 14:45:55

Spring Fram

2011-12-26 09:17:23

JavaSpring

2021-01-05 05:36:39

設計Spring Boot填充

2021-12-28 11:13:05

安全認證 Spring Boot

2024-01-16 08:17:29

Mybatis驗證業(yè)務

2024-02-23 10:33:34

SpringBean容器

2021-04-28 06:26:11

Spring Secu功能實現(xiàn)源碼分析

2024-08-05 08:45:35

SpringKafkaSCRAM

2022-07-11 09:00:37

依賴配置文件Mybati

2012-02-23 12:53:40

JavaPlay Framew

2019-09-09 06:30:06

Springboot程序員開發(fā)

2024-10-14 13:30:20

2017-09-20 09:46:38

Spring BootSpring Clou內存

2023-11-02 18:01:24

SpringMVC配置
點贊
收藏

51CTO技術棧公眾號

校园春色亚洲| 瑟瑟视频在线免费观看| 91精品短视频| 欧美日韩国产在线看| 久久精品二区| 五月激情丁香网| 91成人超碰| 亚洲国产高清福利视频| 青青在线视频观看| 粗大黑人巨茎大战欧美成人| 成人免费视频免费观看| 日本91av在线播放| 国产精品视频一区二区在线观看| 亚洲高清在线一区| 色综合欧美在线| 亚洲午夜精品久久| 高潮一区二区三区乱码| 日韩经典一区二区| 欧美成人合集magnet| 喷水视频在线观看| 亚洲国产天堂| 欧美视频中文字幕在线| 中文精品视频一区二区在线观看| 人妻无码中文字幕| 久久成人麻豆午夜电影| 91精品国产九九九久久久亚洲| 成人免费网站黄| 亚洲成人黄色| 欧美日韩国产片| 国产美女网站在线观看| 好操啊在线观看免费视频| 91亚洲精品久久久蜜桃网站 | 三级黄色在线观看| 全球av集中精品导航福利| 欧美美女一区二区| 欧美污视频网站| 国产盗摄一区二区| 亚洲图片欧美激情| 色噜噜色狠狠狠狠狠综合色一| 蜜臀久久99精品久久久| 国产一区二区美女| 国产精品久久久久久五月尺| 天天综合天天干| 在线观看日韩av电影| 久久久精品国产网站| 欧洲美熟女乱又伦| 免费av一区| 亚洲精品国精品久久99热| 性折磨bdsm欧美激情另类| 91丨精品丨国产| 欧美色倩网站大全免费| 日韩欧美精品在线观看视频| 嗯啊主人调教在线播放视频| 亚洲资源在线观看| 波多野结衣与黑人| 国产乱色在线观看| 亚洲欧洲综合另类在线 | 国内自拍一区| 美日韩精品免费视频| av在线免费播放网址| 欧美久久综合网| 亚洲欧美日韩中文在线| 精品无码人妻少妇久久久久久| 91麻豆精品国产91久久久久推荐资源| 制服丝袜中文字幕一区| 久久综合在线观看| 高清久久精品| 日韩午夜激情av| 18禁一区二区三区| 超碰成人在线免费| 亚洲高清色综合| 国产 中文 字幕 日韩 在线| 天堂资源在线亚洲| 亚洲欧洲xxxx| 欧洲美熟女乱又伦| 天天综合一区| 欧美国产日韩视频| 国产成人愉拍精品久久| 久久成人亚洲| 国产精品视频永久免费播放 | 91精品国产美女浴室洗澡无遮挡| 97人人爽人人| 亚洲日本va中文字幕| 精品国产百合女同互慰| 一级特级黄色片| 免费视频一区三区| 色综合影院在线| 欧美日韩精品一区二区三区视频播放 | 日韩亚洲国产精品| 欧美亚洲国产日本| 中文在线免费看视频| 激情深爱一区二区| 成人片在线免费看| 免费理论片在线观看播放老| 欧美激情一区二区三区在线| 香蕉精品视频在线| 免费毛片在线看片免费丝瓜视频 | 亚洲天堂免费在线| 日本美女黄色一级片| 国语自产精品视频在线看8查询8| 69av在线视频| 亚洲图片欧美在线| 成人中文字幕电影| 日本不卡免费新一二三区| 麻豆视频在线观看免费网站| 亚洲综合色婷婷| 欧美精品色婷婷五月综合| 欧美一级免费| 国产丝袜高跟一区| 亚洲综合视频网站| 欧美亚洲一区| aa成人免费视频| 免费一级毛片在线观看| 有坂深雪av一区二区精品| 欧美精品第三页| 欧美激情三级| 亚洲午夜精品视频| 国产成人啪精品午夜在线观看| 免费在线视频一区| 久久66热这里只有精品| gogo在线观看| 欧美性猛片xxxx免费看久爱| 亚洲色偷偷色噜噜狠狠99网| 久久国产电影| 国产成人精品最新| 欧美自拍第一页| 日韩美女啊v在线免费观看| 欧美视频第三页| 一区二区在线视频观看| 色噜噜狠狠狠综合曰曰曰88av | 欧美亚洲一区三区| 日本黄色动态图| 欧美精品国产一区| 国产精品三级在线| 国产剧情在线观看| 天天做天天摸天天爽国产一区| 天堂av手机在线| 久久久综合色| 国产精品免费一区豆花| 日韩毛片在线一区二区毛片| 亚洲国产成人va在线观看天堂| 成人黄色一级大片| 日韩在线欧美| 国产精品啪视频| 国产视频网站在线| 一本到一区二区三区| 亚洲av成人片色在线观看高潮 | 日韩精品福利一区二区三区| 欧美日韩第一页| 99热这里只有精品66| 国产精品国模大尺度视频| 中文字幕第80页| 国产精品午夜一区二区三区| 欧美一区二区三区精品电影| 香蕉视频免费看| 欧美日韩国产丝袜另类| 狠狠人妻久久久久久综合蜜桃| 99精品热视频只有精品10| 国产精品国产三级国产专区53 | 亚洲人在线观看视频| 亚洲午夜av在线| 一二三区视频在线观看| 亚洲一级毛片| 99久久99久久精品国产片| 日本中文字幕中出在线| 精品国产青草久久久久福利| 欧美精品99久久久| 成人精品视频一区二区三区尤物| www精品久久| 欧美男人操女人视频| 欧美中文在线视频| 国产51人人成人人人人爽色哟哟| 在线免费视频一区二区| 五月天婷婷丁香网| 国产综合久久久久久久久久久久| 国产资源第一页| 999久久久久久久久6666| 98精品国产高清在线xxxx天堂| 日韩欧美在线观看一区二区| 欧美性生活大片视频| 欧美一区免费观看| 成人性色生活片| 丰满人妻中伦妇伦精品app| 精品视频亚洲| 91精品久久香蕉国产线看观看| 国产乱妇乱子在线播视频播放网站| 亚洲国产高清福利视频| 欧美成人一区二区视频| 亚洲欧美二区三区| 中文字幕影片免费在线观看| 日韩av网站免费在线| 日本三日本三级少妇三级66| 九九热hot精品视频在线播放| 欧美性受xxxx黑人猛交| 成人精品一区二区三区校园激情| 欧美乱熟臀69xxxxxx| 动漫精品一区一码二码三码四码| 久久婷婷国产综合国色天香 | 国产一区二区三区精品欧美日韩一区二区三区 | 日韩欧美亚洲一二三区| 天堂av免费在线| www.欧美亚洲| 伊人国产在线视频| 精品动漫一区| 三年中文高清在线观看第6集| 大型av综合网站| 国产精选久久久久久| 高潮在线视频| 久久天天躁狠狠躁老女人| 天堂国产一区二区三区| 7777女厕盗摄久久久| 草久视频在线观看| 亚洲精品中文在线观看| 日本乱子伦xxxx| av中文字幕在线不卡| 五月激情婷婷在线| 国产精品久久久久9999高清| 国产树林野战在线播放| 久久不见久久见国语| 国产精品免费观看高清| av在线国产精品| 国产激情久久久久| 蜜桃视频在线网站| 欧美高清视频在线| 麻豆电影在线播放| 国产亚洲精品久久久| 肉丝一区二区| 亚洲成人激情图| www.成人在线观看| 91.成人天堂一区| 五月激情丁香网| 欧美午夜精品在线| 国产无码精品一区二区| 亚洲乱码精品一二三四区日韩在线 | 日韩欧美国产另类| 精品久久久国产精品999| 九九热只有精品| 亚洲视频一区在线观看| 国产又粗又黄又猛| 国产喂奶挤奶一区二区三区| 女尊高h男高潮呻吟| 粉嫩高潮美女一区二区三区 | 亚洲一区二区三区四区电影| 国产一区在线播放| 青青久久精品| 成人av电影天堂| 免费一区二区三区四区| 日本久久精品视频| 天堂а√在线最新版中文在线| 欧美精品第一页在线播放| 91在线中字| 欧美另类高清videos| 99在线播放| 久久99国产综合精品女同| www久久日com| 欧美日韩福利视频| www.综合网.com| 久久免费国产精品1| 91吃瓜在线观看| 欧美伦理91i| 俺来也官网欧美久久精品| 欧美国产乱视频| 国产福利电影在线播放| 91高潮精品免费porn| 欧洲av不卡| 国产日韩欧美在线视频观看| 91精品福利观看| 97人人模人人爽人人少妇| 成人h动漫精品一区二区器材| 国产精品一区二区三区免费| 日本亚洲不卡| 无遮挡亚洲一区| 影音先锋日韩精品| www.av91| 日韩精品91亚洲二区在线观看| 艹b视频在线观看| 国产精品白丝jk黑袜喷水| 老熟女高潮一区二区三区| 99久久亚洲一区二区三区青草 | 四季av日韩精品一区| 亚洲欧美色婷婷| 国产高清视频免费最新在线| 日韩中文有码在线视频| 男女视频在线| 秋霞av国产精品一区| 欧美激情不卡| 国产乱码精品一区二区三区中文| 亚洲电影一级片| 伊人av成人| 在线欧美三区| 亚洲性生活网站| 国内精品国产成人| 第四色在线视频| 国产精品福利影院| 国产午夜福利片| 日韩欧美亚洲范冰冰与中字| 国产精品久久久久久免费免熟| 亚洲成人在线视频播放| porn亚洲| 91av在线播放视频| 欧美黄色网络| 久久婷婷人人澡人人喊人人爽| 水蜜桃精品av一区二区| 午夜免费福利小电影| 久久 天天综合| 欧美做受喷浆在线观看| 亚洲免费在线视频| 无码人妻丰满熟妇区bbbbxxxx | 黄色一区二区在线观看| 91国内精品久久久| 日韩精品在线观看网站| 91香蕉在线观看| 国产91九色视频| 国产精品115| 一区二区三区日韩视频| 丝袜国产日韩另类美女| 性xxxxxxxxx| 亚洲视频资源在线| 国产一级片一区二区| 日韩电影第一页| 日本性爱视频在线观看| 国产精品视频xxx| 红桃成人av在线播放| 欧美午夜性视频| 国产激情91久久精品导航 | 亚洲成人免费观看| 91欧美日韩麻豆精品| 亚洲香蕉成人av网站在线观看| 波多野结衣乳巨码无在线观看| 91在线观看免费观看| 成人aaaa| 天天操天天爽天天射| 久久免费看少妇高潮| 成年人免费看毛片| 日韩欧美在线观看一区二区三区| 欧美精品videos另类| 国产精品久久一| 久久不见久久见免费视频7| 女人和拘做爰正片视频| 成人ar影院免费观看视频| 麻豆影视在线播放| 日韩三级免费观看| 福利视频在线| 91沈先生在线观看| 亚洲草久电影| 中文字幕亚洲影院| 中文字幕一区二区视频| 在线观看毛片视频| 色777狠狠综合秋免鲁丝| 韩日一区二区| 伊人av成人| 韩国一区二区三区| 玖玖爱这里只有精品| 日韩一区二区精品葵司在线| 黄色成人在线| 亚洲自拍偷拍色图| 欧美视频在线观看| 在线播放第一页| 午夜精品福利在线| 五月色婷婷综合| 欧美中文在线字幕| 俺要去色综合狠狠| 欧美成人福利在线观看| 最近日韩中文字幕| 精品人妻一区二区三区换脸明星 | 亚洲高清不卡一区| 久国产精品韩国三级视频| 欧美精品一区二区蜜桃| 亚洲精品一区二区精华| 午夜激情电影在线播放| 欧美一区二区三区四区夜夜大片| 日韩中文字幕不卡| 日韩三级久久久| 欧美成人一区二区三区在线观看| a级片在线免费观看| 欧美日韩精品免费观看| 青娱乐精品视频| 国产高潮国产高潮久久久91 | bbbbbbbbbbb在线视频| 成人深夜直播免费观看| 国产精品扒开腿做爽爽爽软件| 在线免费观看污视频| 91国偷自产一区二区三区成为亚洲经典 | 欧洲黄色一级视频| 欧美韩国日本一区| www.天堂在线| 欧美一区亚洲一区| 婷婷另类小说| 懂色av粉嫩av蜜乳av| 欧美日韩国产美女| 9765激情中文在线| 亚洲精品白虎| 成人免费av网站| 中文字幕av在线免费观看| 欧美成人午夜免费视在线看片| 日本中文字幕在线一区| 亚洲一区二区三区观看| 亚洲国产一区二区三区| av电影在线网| 国产精品一码二码三码在线|