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

玩轉SpringBoot—啟動源碼及外部化配置

開發 架構
構造方法內會調用枚舉WebApplicationType的deduceFromClasspath方法獲得應用類型并設置當前應用是普通web應用、響應式web應用還是非web應用。

學習目標

  • 理解springboot的總體啟動流程,并能口述大概
  • 理清配置文件的加載流程

第1章 main入口

public static void main(String[] args) {
    //代碼很簡單SpringApplication.run();
	SpringApplication.run(ConsumerApp.class, args);
}
public static ConfigurableApplicationContext run(Class<?> primarySource,
                                                 String... args) {
    //這個里面調用了run() 方法,我們轉到定義
    return run(new Class<?>[] { primarySource }, args);
}
//這個run方法代碼也很簡單,就做了兩件事情
//1、new了一個SpringApplication() 這么一個對象
//2、執行new出來的SpringApplication()對象的run()方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
                                                 String[] args) {
    return new SpringApplication(primarySources).run(args);
}

上面代碼主要做了兩件事情。

  • 第一步new了一個SpringApplication對象
  • 第二步調用了run()方法。

一、SpringApplication

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		//1、先把主類保存起來
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		//2、判斷運行項目的類型
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		//3、掃描當前路徑下META-INF/spring.factories文件的,加載ApplicationContextInitializer接口實例
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		//4、掃描當前路徑下META-INF/spring.factories文件的,加載ApplicationListener接口實例
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
}

1、判斷運行環境

構造方法內會調用枚舉WebApplicationType的deduceFromClasspath方法獲得應用類型并設置當前應用是普通web應用、響應式web應用還是非web應用。

this.webApplicationType = WebApplicationType.deduceFromClasspath();

deduceFromClasspath方法由枚舉WebApplicationType提供,具體實現如下:

static WebApplicationType deduceFromClasspath() {
    //當classpath下只存在org.springframework.web.reactive.DispatcherHandler,
    //且不存在org.springframework.web.servlet.DispatcherServlet,也不存在
    //org.glassfish.jersey.servlet.ServletContainer則運行環境為reactive,該模式是非阻塞模式
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
        && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}

推斷的過程中重點調用了ClassUtils.isPresent()方法,用來判斷指定類名的類是否存在,是否可以進行加載。ClassUtils.isPresent()方法源代碼如下:

public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
    try {
        forName(className, classLoader);
        return true;
    }
    catch (IllegalAccessError err) {
        throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
                                        className + "]: " + err.getMessage(), err);
    }
    catch (Throwable ex) {
        // Typically ClassNotFoundException or NoClassDefFoundError...
        return false;
    }
}

isPresent()方法調用了forName()方法,如果在調用forName()方法的過程中出現異常則返回false,也就是目標類不存在。否則,返回true。

看一下forName()方法的部分代碼:

public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
			throws ClassNotFoundException, LinkageError {

	// 此處省略一些非空和基礎類型的判斷邏輯代碼

	ClassLoader clToUse = classLoader;
	if (clToUse == null) {
	    //如果為空則獲取默認classLoader
		clToUse = getDefaultClassLoader();
	}
	try {
	    // 返回加載戶的Class。
		return Class.forName(name, false, clToUse);
	} catch (ClassNotFoundException ex) {
	    // 如果直接加載類出現異常,則嘗試加載內部類。
		int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
		if (lastDotIndex != -1) {
		    // 拼接內部類
			String innerClassName =
					name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
			try {
				return Class.forName(innerClassName, false, clToUse);
			}
			catch (ClassNotFoundException ex2) {
				// Swallow - let original exception get through
			}
		}
		throw ex;
	}
}

通過以上核心代碼,可得知forName()方法主要做的事情就是獲得類加載器,嘗試直接加載類,如果失敗則嘗試加載該類的內部類,如果依舊失敗,則拋出異常。

因此,整個應用類型的推斷分以下步驟:

  • SpringBoot調用SpringApplication構造方法;
  • SpringApplication構造方法調用枚舉類的類型推斷方法deduceFromClasspath()。
  • deduceFromClasspath()方法通過ClassUtils.isPresent()返回結果為true或false來確定是否加載成功指定的類。
  • ClassUtils.isPresent()方法通過調用forName()方法并捕獲異常來確定是否能夠成功加載該類。
  • forName()方法通過嘗試加載指定類和指定類的內部類來確定該類是否存在,存在則返回該類,不存在則拋異常。

在類型推斷的過程中枚舉類WebApplicationType定義了具體去加載哪些類:

private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

private static final String WEBMVC_INDICATOR_CLASS = "org.springframework."
    + "web.servlet.DispatcherServlet";

private static final String WEBFLUX_INDICATOR_CLASS = "org."
    + "springframework.web.reactive.DispatcherHandler";

private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
  • 如果應用程序存在DispatcherHandler并且不存在DispatcherServlet和ServletContainer則為響應式web應用,需加載并啟動內嵌的響應式web服務。
  • 如果應用程序不包含Servlet和ConfigurableWebApplicationContext則為普通應用程序。
  • 其他情況則為基于servlet的web應用,需加載并啟動內嵌的web服務。

2、初始化器和監聽器

利用SPI機制掃描 META-INF/spring.factories 這個文件,并且加載ApplicationContextInitializer、ApplicationListener 接口實例。

  • ApplicationContextInitializer 這個類當springboot上下文Context初始化完成后會調用。
  • ApplicationListener 當springboot啟動時事件change后都會觸發。

總結:上面就是SpringApplication初始化的代碼,new SpringApplication()沒做啥事情 ,利用SPI機制主要加載了META-INF/spring.factories 下面定義的事件監聽器接口實現類。

二、執行run方法

public ConfigurableApplicationContext run(String... args) {

    <!--1、這個是一個計時器,沒什么好說的-->
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    
    <!--2、這個也不是重點,就是設置了一些環境變量-->
    configureHeadlessProperty();
 
    <!--3、獲取事件監聽器SpringApplicationRunListener類型,并且執行starting()方法-->
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);

    try {
        <!--4、把參數args封裝成DefaultApplicationArguments,這個了解一下就知道-->
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

        <!--5、這個很重要準備環境了,并且把環境跟spring上下文綁定好,并且執行environmentPrepared()方法-->
            //準備容器環境、這里會加載配置文件。在這個方法里面會調用所有監聽器Listener的onApplicationEvent(event);
            // 此時有一個與配置文件相關的監聽器就會被加載`ConfigFileApplicationListener`
        ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);

        <!--6、判斷一些環境的值,并設置一些環境的值-->
        configureIgnoreBeanInfo(environment);

        <!--7、打印banner-->
        Banner printedBanner = printBanner(environment);


        <!--8、創建上下文,根據項目類型創建上下文-->
        context = createApplicationContext();
		context.setApplicationStartup(this.applicationStartup);
        
        <!--9、準備上下文,執行完成后調用contextPrepared()方法,contextLoaded()方法-->
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

        <!--10、這個是spring啟動的代碼了,這里就回去里面就回去掃描并且初始化單實列bean了-->
        //這個refreshContext()加載了bean,還啟動了內置web容器,需要細細的去看看
        refreshContext(context);

        <!--11、啥事情都沒有做-->
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }

        <!--12、執行ApplicationRunListeners中的started()方法-->
        listeners.started(context);

        <!--執行Runner(ApplicationRunner和CommandLineRunner)-->
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

第2章 環境變量及配置

一、prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                  DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
    // 創建和配置環境變量
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach(environment);
    listeners.environmentPrepared(bootstrapContext, environment);
    DefaultPropertiesPropertySource.moveToEnd(environment);
    Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
                 "Environment prefix cannot be set via properties.");
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                                                                                               deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

二、getOrCreateEnvironment

/**
*  該方法根據webApplicationType判斷當前項目是什么類型項目
*/
private ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
    }
}

//webApplicationType是在new SpringApplication方法中通過WebApplicationType.deduceFromClasspath()進行賦值

枚舉WebApplicationType中定義了三個應用類型:

  • NONE:應用程序不作為web應用啟動,不啟動內嵌的服務。
  • SERVLET:應用程序以基于servlet的web應用啟動,需啟動內嵌servlet web服務。
  • REACTIVE:應用程序以響應式web應用啟動,需啟動內嵌的響應式web服務。

這里調用newStandardServletEnvironment()方法。

StandardServletEnvironment繼承了StandardEnvironment方法,StandardEnvironment又繼承了AbstractEnvironment方法;在AbstractEnvironment方法中調用了customizePropertySources方法。

public AbstractEnvironment() {
    customizePropertySources(this.propertySources);
}

customizePropertySources方法會回調StandardServletEnvironment方法中的customizePropertySources方法。

protected void customizePropertySources(MutablePropertySources propertySources) {
    propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
    propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
    if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
        propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
    }
    //在這里又調用了父類StandardEnvironment的方法
    super.customizePropertySources(propertySources);
}

到這里為止propertySources里面就加載了servletConfigInitParams、servletContextInitParams、systemProperties、systemEnvironment。

然后回到prepareEnvironment方法中,在listeners.environmentPrepared(bootstrapContext, environment);方法中去進行監聽。

三、environmentPrepared

void environmentPrepared(ConfigurableEnvironment environment) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.environmentPrepared(environment);
    }
}

繼續進入environmentPrepared方法,會進入到SpringApplicationRunListener接口,這個接口在run方法中的getRunListeners里面獲取,最終是在sprin.factories里面進行加載實現類EventPublishingRunListener,執行的是EventPublishingRunListener類中的environmentPrepared方法。

public void environmentPrepared(ConfigurableEnvironment environment) {
    this.initialMulticaster
        .multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}

multicastEvent

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

invokeListener

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            doInvokeListener(listener, event);
        }
        catch (Throwable err) {
            errorHandler.handleError(err);
        }
    }
    else {
        doInvokeListener(listener, event);
    }
}

doInvokeListener

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
        String msg = ex.getMessage();
        if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
            // Possibly a lambda-defined listener which we could not resolve the generic event type for
            // -> let's suppress the exception and just log a debug message.
            Log logger = LogFactory.getLog(getClass());
            if (logger.isTraceEnabled()) {
                logger.trace("Non-matching event type for listener: " + listener, ex);
            }
        }
        else {
            throw ex;
        }
    }
}

進入ConfigFileApplicationListener實現類中的onApplicationEvent方法。

onApplicationEvent

public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ApplicationEnvironmentPreparedEvent) {
        //在這個方法里面讀取配置文件
        onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
    }
    if (event instanceof ApplicationPreparedEvent) {
        onApplicationPreparedEvent(event);
    }
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
    List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
    postProcessors.add(this);
    AnnotationAwareOrderComparator.sort(postProcessors);
    for (EnvironmentPostProcessor postProcessor : postProcessors) {
        //進入
        postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
    }
}
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
    //進入
    addPropertySources(environment, application.getResourceLoader());
}
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
    RandomValuePropertySource.addToEnvironment(environment);
    //load方法是讀取配置文件的核心方法
    new Loader(environment, resourceLoader).load();
}
void load() {
    FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
                                 (defaultProperties) -> {
                                     this.profiles = new LinkedList<>();
                                     this.processedProfiles = new LinkedList<>();
                                     this.activatedProfiles = false;
                                     this.loaded = new LinkedHashMap<>();
                                     initializeProfiles();
                                     while (!this.profiles.isEmpty()) {
                                         Profile profile = this.profiles.poll();
                                         if (isDefaultProfile(profile)) {
                                             addProfileToEnvironment(profile.getName());
                                         }
                                         load(profile, this::getPositiveProfileFilter,
                                              addToLoaded(MutablePropertySources::addLast, false));
                                         this.processedProfiles.add(profile);
                                     }
                                     load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
                                     addLoadedPropertySources();
                                     applyActiveProfiles(defaultProperties);
                                 });
}

createApplicationContext

一起來看下context = createApplicationContext(); 這段代碼,這段代碼主要是根據項目類型創建上下文,并且會注入幾個核心組件類。

protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			switch (this.webApplicationType) {
			case SERVLET:
				contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
				break;
			case REACTIVE:
				contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
				break;
			default:
				contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
			}
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
		}
	}
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
public AnnotationConfigServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
	   super(beanFactory);
       //1:會去注入一些spring核心組件
	   this.reader = new AnnotatedBeanDefinitionReader(this);
	   this.scanner = new ClassPathBeanDefinitionScanner(this);

}

Web類型項目創建上下文對象AnnotationConfigServletWebServerApplicationContext 。這里會把 ConfigurationClassPostProcessor 、AutowiredAnnotationBeanPostProcessor 等一些核心組件加入到Spring容器。

五、refreshContext

下面一起來看下refreshContext(context) 這個方法,這個方法啟動spring的代碼加載了bean,還啟動了內置web容器。

private void refreshContext(ConfigurableApplicationContext context) {
        // 轉到定義看看
		refresh(context);
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
}
protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        //看看refresh()方法去
		((AbstractApplicationContext) applicationContext).refresh();

}

轉到AbstractApplicationContext - >refresh()方法里面發現這是spring容器啟動代碼。

/**
* 加載或刷新一個持久化的配置,可能是XML文件、屬性文件或關系數據庫模式。
* 由于這是一種啟動方法,如果失敗,應該銷毀已經創建的單例,以避免懸空資源。
* 換句話說,在調用該方法之后,要么全部實例化,要么完全不實例化。
* @throws 如果bean工廠無法初始化,則拋出 BeansException 異常
* @throws 如果已經初始化且不支持多次刷新,則會拋出 IllegalStateException 異常
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
    //加載或刷新配置前的同步處理
    synchronized (this.startupShutdownMonitor) {
        // 為刷新而準備此上下文
        prepareRefresh();

        // 告訴子類去刷新內部bean工廠。
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 準備好bean工廠,以便在此上下文中使用。
        prepareBeanFactory(beanFactory);

        try {
            // 允許在上下文子類中對bean工廠進行后置處理。
            postProcessBeanFactory(beanFactory);

            // 調用在上下文中注冊為bean的工廠處理器。
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注冊攔截bean創建的bean處理器。
            registerBeanPostProcessors(beanFactory);

            // 初始化此上下文的 message resource 消息資源。
            initMessageSource();

            // 為這個上下文初始化事件多路廣播器。
            initApplicationEventMulticaster();

            // 初始化特定上下文子類中的其他特殊bean。
            onRefresh();

            // 注冊監聽器(檢查監聽器的bean并注冊它們)。
            registerListeners();

            // 實例化所有剩余的(非 lazy-init 懶初始化的)單例。
            finishBeanFactoryInitialization(beanFactory);

            // 最后一步: 發布相應的事件。
            finishRefresh();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
            }

            // 銷毀已經創建的單例,以避免懸空資源。
            destroyBeans();

            // 重置 'active' 表示.
            cancelRefresh(ex);

            // 將異常傳播給調用者。
            throw ex;
        }

        finally {
            // 重置Spring內核中的共用的緩存,因為我們可能再也不需要單例bean的元數據了……
            resetCommonCaches();
        }
    }
}
責任編輯:姜華 來源: 今日頭條
相關推薦

2020-10-26 15:01:02

Spring Boot源碼參數

2022-10-08 08:01:17

Spring源碼服務

2023-03-26 08:15:04

代碼配置Spring

2023-03-20 07:32:26

配置代碼Spring

2024-01-05 08:38:20

SpringBeanScope

2023-09-28 09:17:18

SpringBootBean

2023-10-10 09:07:23

2023-09-08 09:10:33

SpringBoot微服務架構

2010-09-06 14:32:55

CISCO PPP配置

2015-11-23 09:50:15

JavaScript模塊化SeaJs

2023-06-15 14:09:00

解析器Servlet容器

2010-01-18 10:37:51

端口監控配置

2012-11-05 14:45:06

交換機

2014-06-16 11:17:12

入侵檢測OSSEC日志分析

2017-01-09 15:09:45

Linux初始化配置

2010-09-01 16:35:12

SQL刪除存儲過程

2015-09-15 14:09:29

2015-09-15 14:09:32

2023-06-30 07:51:44

springboot初始化邏輯

2009-11-10 11:21:41

點贊
收藏

51CTO技術棧公眾號

欧美一区二区色| 日韩一区二区免费高清| 欧美日韩一区二| 岳乳丰满一区二区三区| 在线成人超碰| 日韩精品亚洲精品| 91极品尤物在线播放国产| 91最新在线视频| 99国产精品视频免费观看| 国产精品入口夜色视频大尺度| 国产精品视频一区二区三 | 日本一区二区在线播放| 多男操一女视频| 偷窥自拍亚洲色图精选| 91精品国产日韩91久久久久久| 亚洲熟妇av日韩熟妇在线| 91se在线| 91麻豆成人久久精品二区三区| 91精品视频免费| 无码人妻精品一区二区三区9厂| 欧美激情五月| 视频一区视频二区国产精品| 三级男人添奶爽爽爽视频| 成人日韩视频| 欧美色视频一区| 日韩免费视频播放| 亚洲综合影视| 中文字幕日韩精品一区| 日本一区二区在线视频| 国产91免费看| 国产福利不卡视频| 成人写真视频福利网| 中文字幕av第一页| 免费日韩av片| 97欧美精品一区二区三区| 欧美高清视频一区二区三区| 国产精品毛片久久| 国产一区二区日韩| 色无极影院亚洲| 要久久爱电视剧全集完整观看| 亚洲第一色在线| 男生和女生一起差差差视频| 亚洲欧美专区| 欧美电影一区二区| 亚洲精品20p| 久久青草免费| 欧美色偷偷大香| 亚洲人视频在线| 欧美成人aaa| 欧美美女网站色| 日韩av自拍偷拍| 成人永久在线| 日韩区在线观看| wwwxx日本| 国产精品极品在线观看| 亚洲精品乱码久久久久久金桔影视| 91精品国产高清91久久久久久| 午夜电影一区| 亚洲成人动漫在线播放| 久久人人妻人人人人妻性色av| 久本草在线中文字幕亚洲| 精品国精品自拍自在线| 丝袜熟女一区二区三区| 亚洲黄色录像| 尤物精品国产第一福利三区| 手机av在线不卡| 婷婷综合伊人| 欧美激情一区二区三级高清视频| 懂色av.com| 亚洲欧美激情诱惑| 国产精品久久久久91| 亚洲一级视频在线观看| 国产精品中文字幕欧美| 国产精品乱码一区二区三区| 免费a级毛片在线观看| 亚洲国产精品二十页| 在线精品亚洲一区二区| 一二三四区在线观看| 激情成人中文字幕| 免费看a级黄色片| av在线国产精品| 亚洲国产欧美一区二区丝袜黑人 | 国产中文字幕二区| 日本综合字幕| 51久久夜色精品国产麻豆| 麻豆av免费看| 精品国产成人| 欧美激情视频在线| 东京热一区二区三区四区| 久国产精品韩国三级视频| 国产高清在线一区二区| 春暖花开成人亚洲区| 亚洲精品福利视频网站| 日韩欧美在线播放视频| 国产精品视频一区视频二区| 日韩精品视频免费专区在线播放| 大吊一区二区三区| 国产精品亚洲综合久久| 国产日韩在线观看av| 欧美老女人在线| 国产福利短视频| 久久久久国产| 国产成人精品电影久久久| 国产女主播福利| 久久久国产精品不卡| 久久久天堂国产精品| 亚洲精品555| 亚洲黄页视频免费观看| 国产福利视频网站| 美女视频一区免费观看| 俄罗斯精品一区二区三区| 成人亚洲综合天堂| 亚洲国产精品久久久久婷婷884 | 中国一级免费毛片| 精品一区二区三区日韩| 欧美一区二区三区四区夜夜大片 | jizz日本免费| 欧美jizzhd精品欧美巨大免费| 国产91在线播放九色快色| 丰满人妻一区二区三区无码av | 成人爽a毛片一区二区免费| 日韩免费av一区二区三区| tube8在线hd| 日韩三级精品电影久久久| 欧美aaa级片| 久久久xxx| 蜜桃av噜噜一区二区三| 国内在线免费视频| 日韩欧美在线观看一区二区三区| 在线免费看视频| 日韩精品亚洲专区| 免费毛片一区二区三区久久久| 91av久久| 亚洲国模精品一区| 久久亚洲国产成人精品性色| 国产精品一卡二| 91制片厂免费观看| 涩涩涩久久久成人精品| 中文字幕av一区中文字幕天堂 | 精品国产伦理网| 清纯粉嫩极品夜夜嗨av| 国产麻豆成人精品| 99视频精品全部免费看| 精品国产一区二| 欧美日韩不卡合集视频| www.久久成人| 亚洲一区免费在线观看| 亚洲美女高潮久久久| 国精品一区二区三区| 国产精品一区二区三区在线观 | 蜜芽tv福利在线视频| 一本到三区不卡视频| 免费在线观看成年人视频| 国产精品美女| 欧美三级电影在线播放| 国产在线|日韩| 精品国产一区二区三区四区在线观看 | 日韩欧美国产网站| 天天躁日日躁aaaa视频| 日韩精品电影一区亚洲| 亚洲一区二区三区精品视频 | 69av一区二区三区| 波多野结衣爱爱视频| 国产成人综合视频| 人妻少妇精品无码专区二区| 色老板在线视频一区二区| 日本精品性网站在线观看| www在线播放| 日韩一区二区中文字幕| 国产亚洲精品久久777777| 97久久超碰国产精品| 黄色片久久久久| 久久精品国产99久久| 91视频免费进入| 国产精品蜜芽在线观看| 在线播放国产一区二区三区| 91精品人妻一区二区三区果冻| 亚洲精品美国一| 人妻熟女aⅴ一区二区三区汇编| 日韩高清在线不卡| 三级在线免费观看| 先锋影音国产精品| 国产日韩综合一区二区性色av| 午夜伦理大片视频在线观看| 精品偷拍各种wc美女嘘嘘| 亚洲一区二区三区高清视频| 亚洲一区二区三区四区不卡| 国产人妻大战黑人20p| 国产麻豆精品在线观看| 国产亚洲精品网站| 图片区亚洲欧美小说区| 久久99精品久久久久久青青日本| 成人做爰免费视频免费看| 色在人av网站天堂精品| 国产天堂在线| 337p日本欧洲亚洲大胆色噜噜| 天堂网免费视频| 亚洲一区二区三区在线| 四季av中文字幕| 成人美女在线观看| 色呦色呦色精品| 丝袜亚洲另类丝袜在线| 日韩成人手机在线| 97久久夜色精品国产| 久久久99爱| 91精品国产乱码久久久竹菊| 国产精品国语对白| 涩涩涩在线视频| 欧美大片网站在线观看| 米奇777四色精品人人爽| 亚洲美女精品久久| 国产刺激高潮av| 制服丝袜日韩国产| 国产乱码77777777| 图片区小说区区亚洲影院| 亚洲综合视频网站| 久久久久久久久久久99999| 白丝校花扒腿让我c| 麻豆精品一区二区av白丝在线| 日日鲁鲁鲁夜夜爽爽狠狠视频97 | 性欧美videos另类hd| 欧美三级三级三级爽爽爽| 久久99国产综合精品免费| 一区二区三区美女| 成人高潮免费视频| 成人欧美一区二区三区1314| 国产成人福利在线| 久久综合久久鬼色| www.免费av| av不卡在线观看| 精品人妻一区二区免费| 国产高清在线观看免费不卡| 中文字幕永久有效| 老色鬼精品视频在线观看播放| 精品国产成人av在线免| 亚洲一区欧美二区| 国产精品无码av在线播放| 亚洲人成高清| 欧美精品久久久久久久自慰| 伊人成人在线| 成人午夜精品久久久久久久蜜臀| 欧美日本免费| 国产精品va在线观看无码| 在线精品视频在线观看高清| 热这里只有精品| 综合激情网站| 国产肉体ⅹxxx137大胆| 亚洲精品乱码久久久久久蜜桃麻豆| 中文字幕无码精品亚洲资源网久久| 欧美视频日韩| 僵尸世界大战2 在线播放| 99精品福利视频| 春日野结衣av| 日韩影院精彩在线| 亚欧在线免费观看| 精品影视av免费| 欧美日韩理论片| 国产91色综合久久免费分享| 扒开伸进免费视频| 粉嫩一区二区三区四区公司1| 欧美日韩黄视频| 手机av免费观看| 欧美日韩一区二区三区视频| 亚洲综合精品在线| 欧美一级淫片007| 高h放荡受浪受bl| 日韩精品在线第一页| 成人资源www网在线最新版| 色妞色视频一区二区三区四区| 久久久久久久久免费视频| 欧美二区乱c黑人| 高清在线视频不卡| 欧美中文字幕精品| 久久久久毛片| 国产欧美日韩亚洲| 国内成人自拍| 亚洲高潮无码久久| 国产日韩一区二区三区在线| 国产三级日本三级在线播放| 韩国成人在线视频| 182在线视频| 中文在线免费一区三区高中清不卡| 日韩精品123区| 欧美日韩国产精品专区 | 91精品国产乱| 四季av日韩精品一区| 在线看国产精品| 欧美韩日亚洲| 国产福利精品av综合导导航| 亚洲一区导航| 久久国产一区| 91超碰国产精品| www.com毛片| 国产一区二区精品久久91| 亚洲最大成人网站| 一区二区三区在线观看动漫| 尤物视频免费观看| 精品免费日韩av| 精品黄色免费中文电影在线播放| 26uuu另类亚洲欧美日本一| 日韩欧美三区| 欧美日本国产精品| 午夜精品网站| 成人亚洲精品777777大片| 不卡的av网站| 四虎永久免费在线| 欧美日韩在线免费视频| 婷婷色在线观看| 久久成年人免费电影| 日韩精品免费观看视频| 九色91在线视频| 欧美日本久久| 国产资源中文字幕| 亚洲国产精品国自产拍av| 天堂网av手机版| 日韩免费成人网| 黄色在线免费看| 国产精品入口福利| 色婷婷精品视频| 和岳每晚弄的高潮嗷嗷叫视频| 国产一区二区三区av电影| 91社区视频在线观看| 欧美日韩国产综合视频在线观看中文| 国产精品人人妻人人爽| 在线观看视频99| 中文字幕av一区二区三区佐山爱| 国产专区一区二区| 国产综合色产| 国产欧美视频一区| 亚洲精品视频在线观看网站| 亚洲中文字幕在线观看| 亚洲午夜av久久乱码| 电影一区二区三| 蜜桃传媒视频麻豆第一区免费观看| 亚洲视频精品| 蜜桃色一区二区三区| 一区二区三区久久| 超碰人人人人人人| 色综合久久久久久中文网| 欧美特黄不卡| 2021国产视频| 国产河南妇女毛片精品久久久| 久久精品一区二区三区四区五区| 欧美日韩中字一区| 日本亚洲精品| 91视频-88av| 欧美1区视频| 亚洲欧美激情一区二区三区| 亚洲狠狠丁香婷婷综合久久久| av 一区二区三区| 欧美日韩第一视频| 国产主播性色av福利精品一区| www.av片| 久久久久久久综合狠狠综合| 国产suv精品一区二区33| 在线精品国产欧美| crdy在线观看欧美| 亚洲色婷婷久久精品av蜜桃| 国产suv精品一区二区883| 国产一级在线视频| 精品一区二区三区四区在线| 欧美美女日韩| av动漫免费观看| 国产丶欧美丶日本不卡视频| 日韩手机在线观看| 亚洲香蕉av在线一区二区三区| 日韩一区二区三区在线免费观看 | 欧美大片在线观看一区二区| 日本在线观看大片免费视频| 国产精品一区二区免费看| 老司机一区二区三区| 免费黄色在线网址| 日韩一区和二区| 伊人久久视频| 亚洲一区二区三区欧美| 丁香婷婷综合五月| 亚洲 日本 欧美 中文幕| xxx欧美精品| 日本一道高清一区二区三区| 五月婷婷深爱五月| 一区二区三区在线视频播放| 日本人妖在线| 91视频-88av| 久久精品九九| 成年人av电影| 精品一区二区亚洲| 精品视频一二| 欧美视频免费播放| 亚洲精品v日韩精品| 日韩av视屏| 51国偷自产一区二区三区的来源| 亚洲美女少妇无套啪啪呻吟| 纪美影视在线观看电视版使用方法| 欧美成人福利视频| 主播大秀视频在线观看一区二区| 久久综合久久久久| 国产精品区一区二区三区| 日本黄色不卡视频| 国产美女主播一区| 国产农村妇女精品一二区|