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

類加載機制的源碼解讀

開發 前端
WebApp 類加載器是每個 Web 應用獨有的,而每個 Web 應用本質上就是一個 Context。 因此,我們理所當然地將目光投向了 Context 的實現類。 Tomcat 中,StandardContext? 是 Context? 的默認實現,而 WebApp 類加載器正是誕生于 StandardContext? 類的 startInternal() 方法中。

前言

繼前文深入剖析雙親委派機制之后,本文將引直接走進具體的代碼實現,一探其真正的實現思路。

源碼閱讀

Tomcat 啟動的起點在于 Bootstrap 類的 main()方法。在 main()方法執行之前,其靜態代碼塊(static{})會率先被執行。因此,我們將首先深入探討靜態代碼塊的運行機制,然后再分析 main()方法的執行流程。

Bootstrap.static{}

static {
    // 獲取用戶目錄
    String userDir = System.getProperty("user.dir");

    // 優先從環境變量獲取 CATALINA_HOME
    String home = System.getProperty(Globals.CATALINA_HOME_PROP);
    File homeFile = null;

    if (home != null) {
        File f = new File(home);
        try {
            homeFile = f.getCanonicalFile();
        } catch (IOException ioe) {
            homeFile = f.getAbsoluteFile();
        }
    }

    // 若環境變量中未獲取到,則嘗試從 bootstrap.jar 所在目錄的上一級目錄獲取
    if (homeFile == null) {
        File bootstrapJar = new File(userDir, "bootstrap.jar");
        if (bootstrapJar.exists()) {
            File f = new File(userDir, "..");
            try {
                homeFile = f.getCanonicalFile();
            } catch (IOException ioe) {
                homeFile = f.getAbsoluteFile();
            }
        }
    }

    // 若以上兩種方式均未獲取到,則使用用戶目錄作為 CATALINA_HOME
    if (homeFile == null) {
        File f = new File(userDir);
        try {
            homeFile = f.getCanonicalFile();
        } catch (IOException ioe) {
            homeFile = f.getAbsoluteFile();
        }
    }

    // 設置 CATALINA_HOME 屬性
    catalinaHomeFile = homeFile;
    System.setProperty(Globals.CATALINA_HOME_PROP, catalinaHomeFile.getPath());

    // 獲取 CATALINA_BASE,若未設置,則使用 CATALINA_HOME 作為 CATALINA_BASE
    String base = System.getProperty(Globals.CATALINA_BASE_PROP);
    if (base == null) {
        catalinaBaseFile = catalinaHomeFile;
    } else {
        File baseFile = new File(base);
        try {
            baseFile = baseFile.getCanonicalFile();
        } catch (IOException ioe) {
            baseFile = baseFile.getAbsoluteFile();
        }
        catalinaBaseFile = baseFile;
    }
    // 設置 CATALINA_BASE 屬性
    System.setProperty(Globals.CATALINA_BASE_PROP, catalinaBaseFile.getPath());
}

在啟動的初始階段,Tomcat 需要確定自身的根目錄(catalina.home)和工作目錄(catalina.base)。 這段代碼描述了尋找這兩個關鍵路徑的邏輯:

  1. 探尋根目錄: 首先,代碼會嘗試從系統環境變量中獲取 catalina.home 的值。 若未找到,則會進一步探尋 bootstrap.jar 所在目錄的上一級目錄,并將該目錄作為 catalina.home。 最終,若仍無法確定 catalina.home,則將當前用戶目錄(user.dir)作為默認值。
  2. 定位工作目錄: 隨后,代碼會嘗試從系統環境變量中獲取 catalina.base 的值。 若未找到,則將 catalina.home 的值作為 catalina.base。

最后,代碼會將最終確定的 catalina.home 和 catalina.base 路徑信息設置為系統屬性,以便在后續的啟動流程中使用。

這段代碼如同為 Tomcat 構建一座穩固的基石,它負責加載并設置 catalina.home 和 catalina.base 相關的信息,為后續的啟動流程奠定基礎。

main()

Tomcat 的 main 方法可概括為兩個主要階段:**初始化 (**init) 和 加載與啟動 (load+start);。

public static void main(String args[]) {
    // 初始化階段  main方法第一次執行的時候,daemon肯定為null,所以直接new了一個Bootstrap對象,然后執行其init()方法
    if (daemon == null) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.init();
        } catch (Throwable t) {
            handleThrowable(t);
            t.printStackTrace();
            return;
        }
        //daemon守護對象設置為bootstrap
        daemon = bootstrap;
    } else {
        // 當作為服務運行時,對stop的調用將在新線程上進行,
        // 因此確保使用正確的類加載器以防止一系列類未找到異常。
        Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
    }

    // 加載與啟動階段
    // 執行守護對象的load方法和start方法
    try {
        String command = "start";
        if (args.length > 0) {
            command = args[args.length - 1];
        }

        if (command.equals("startd")) {
            args[args.length - 1] = "start";
            daemon.load(args);
            daemon.start();
        } else if (command.equals("stopd")) {
            args[args.length - 1] = "stop";
            daemon.stop();
        } else if (command.equals("start")) {
            daemon.setAwait(true);
            daemon.load(args);
            daemon.start();
            if (null == daemon.getServer()) {
                System.exit(1);
            }
        } else if (command.equals("stop")) {
            daemon.stopServer(args);
        } else if (command.equals("configtest")) {
            daemon.load(args);
            if (null == daemon.getServer()) {
                System.exit(1);
            }
            System.exit(0);
        } else {
            log.warn("Bootstrap: command \"" + command + "\" does not exist.");
        }
    } catch (Throwable t) {
        // 展開異常以獲得更清晰的錯誤報告
        if (t instanceof InvocationTargetException &&
                t.getCause() != null) {
            t = t.getCause();
        }
        handleThrowable(t);
        t.printStackTrace();
        System.exit(1);
    }
}

我們點到init()里面去看看~

public void init() throws Exception {
    // 非常關鍵的地方,初始化類加載器s,后面我們會詳細具體地分析這個方法
    initClassLoaders();

    // 設置上下文類加載器為catalinaLoader,這個類加載器負責加載Tomcat專用的類
    Thread.currentThread().setContextClassLoader(catalinaLoader);
    // 暫時略過,后面會講
    SecurityClassLoad.securityClassLoad(catalinaLoader);

    // 使用catalinaLoader加載我們的Catalina類
    // Load our startup class and call its process() method
    if (log.isDebugEnabled())
        log.debug("Loading startup class");
    Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
    Object startupInstance = startupClass.getConstructor().newInstance();

    // 設置Catalina類的parentClassLoader屬性為sharedLoader
    // Set the shared extensions class loader
    if (log.isDebugEnabled())
        log.debug("Setting startup class properties");
    String methodName = "setParentClassLoader";
    Class<?> paramTypes[] = new Class[1];
    paramTypes[0] = Class.forName("java.lang.ClassLoader");
    Object paramValues[] = new Object[1];
    paramValues[0] = sharedLoader;
    Method method =
        startupInstance.getClass().getMethod(methodName, paramTypes);
    method.invoke(startupInstance, paramValues);

    // catalina守護對象為剛才使用catalinaLoader加載類、并初始化出來的Catalina對象
    catalinaDaemon = startupInstance;
}

initClassLoaders 方法是 Tomcat 類加載機制的核心,它負責初始化 Tomcat 的各個類加載器,構建起 Tomcat 獨特的類加載體系。通過分析這個方法,我們可以清晰地驗證上一節提到的 Tomcat 類加載圖。

private void initClassLoaders() {
    try {
        // 創建commonLoader,如果未創建成果的話,則使用應用程序類加載器作為commonLoader
        commonLoader = createClassLoader("common", null);
        if( commonLoader == null ) {
            // no config file, default to this loader - we might be in a 'single' env.
            commonLoader=this.getClass().getClassLoader();
        }
        // 創建catalinaLoader,父類加載器為commonLoader
        catalinaLoader = createClassLoader("server", commonLoader);
        // 創建sharedLoader,父類加載器為commonLoader
        sharedLoader = createClassLoader("shared", commonLoader);
    } catch (Throwable t) {
        // 如果創建的過程中出現異常了,日志記錄完成之后直接系統退出
        handleThrowable(t);
        log.error("Class loader creation threw exception", t);
        System.exit(1);
    }
}

createClassLoader 方法是 Tomcat 類加載器創建的底層方法,它負責根據配置文件 catalina.properties 中的配置信息來創建具體的類加載器實例。 CatalinaProperties.getProperty("xxx") 方法用于從 conf/catalina.properties 文件中獲取指定屬性的值,為 createClassLoader 方法提供必要的配置信息。

private ClassLoader createClassLoader(String name, ClassLoader parent)
    throws Exception {
    // 獲取類加載器待加載的位置,如果為空,則不需要加載特定的位置,使用父類加載返回回去。
    String value = CatalinaProperties.getProperty(name + ".loader");
    if ((value == null) || (value.equals("")))
        return parent;
    // 替換屬性變量,比如:${catalina.base}、${catalina.home}
    value = replace(value);

    List<Repository> repositories = new ArrayList<>();

   // 解析屬性路徑變量為倉庫路徑數組
    String[] repositoryPaths = getPaths(value);

    // 對每個倉庫路徑進行repositories設置。我們可以把repositories看成一個個待加載的位置對象,可以是一個classes目錄,一個jar文件目錄等等
    for (String repository : repositoryPaths) {
        // Check for a JAR URL repository
        try {
            @SuppressWarnings("unused")
            URL url = new URL(repository);
            repositories.add(
                    new Repository(repository, RepositoryType.URL));
            continue;
        } catch (MalformedURLException e) {
            // Ignore
        }

        // Local repository
        if (repository.endsWith("*.jar")) {
            repository = repository.substring
                (0, repository.length() - "*.jar".length());
            repositories.add(
                    new Repository(repository, RepositoryType.GLOB));
        } else if (repository.endsWith(".jar")) {
            repositories.add(
                    new Repository(repository, RepositoryType.JAR));
        } else {
            repositories.add(
                    new Repository(repository, RepositoryType.DIR));
        }
    }
    // 使用類加載器工廠創建一個類加載器
    return ClassLoaderFactory.createClassLoader(repositories, parent);
}

我們來分析一下ClassLoaderFactory.createClassLoader--類加載器工廠創建類加載器。

public static ClassLoader createClassLoader(List<Repository> repositories,
                                            final ClassLoader parent)
    throws Exception {

    if (log.isDebugEnabled())
        log.debug("Creating new class loader");

    // Construct the "class path" for this class loader
    Set<URL> set = new LinkedHashSet<>();
    // 遍歷repositories,對每個repository進行類型判斷,并生成URL,每個URL我們都要校驗其有效性,有效的URL我們會放到URL集合中
    if (repositories != null) {
        for (Repository repository : repositories)  {
            if (repository.getType() == RepositoryType.URL) {
                URL url = buildClassLoaderUrl(repository.getLocation());
                if (log.isDebugEnabled())
                    log.debug("  Including URL " + url);
                set.add(url);
            } else if (repository.getType() == RepositoryType.DIR) {
                File directory = new File(repository.getLocation());
                directory = directory.getCanonicalFile();
                if (!validateFile(directory, RepositoryType.DIR)) {
                    continue;
                }
                URL url = buildClassLoaderUrl(directory);
                if (log.isDebugEnabled())
                    log.debug("  Including directory " + url);
                set.add(url);
            } else if (repository.getType() == RepositoryType.JAR) {
                File file=new File(repository.getLocation());
                file = file.getCanonicalFile();
                if (!validateFile(file, RepositoryType.JAR)) {
                    continue;
                }
                URL url = buildClassLoaderUrl(file);
                if (log.isDebugEnabled())
                    log.debug("  Including jar file " + url);
                set.add(url);
            } else if (repository.getType() == RepositoryType.GLOB) {
                File directory=new File(repository.getLocation());
                directory = directory.getCanonicalFile();
                if (!validateFile(directory, RepositoryType.GLOB)) {
                    continue;
                }
                if (log.isDebugEnabled())
                    log.debug("  Including directory glob "
                        + directory.getAbsolutePath());
                String filenames[] = directory.list();
                if (filenames == null) {
                    continue;
                }
                for (int j = 0; j < filenames.length; j++) {
                    String filename = filenames[j].toLowerCase(Locale.ENGLISH);
                    if (!filename.endsWith(".jar"))
                        continue;
                    File file = new File(directory, filenames[j]);
                    file = file.getCanonicalFile();
                    if (!validateFile(file, RepositoryType.JAR)) {
                        continue;
                    }
                    if (log.isDebugEnabled())
                        log.debug("    Including glob jar file "
                            + file.getAbsolutePath());
                    URL url = buildClassLoaderUrl(file);
                    set.add(url);
                }
            }
        }
    }

    // Construct the class loader itself
    final URL[] array = set.toArray(new URL[set.size()]);
    if (log.isDebugEnabled())
        for (int i = 0; i < array.length; i++) {
            log.debug("  location " + i + " is " + array[i]);
        }

    // 從這兒看,最終所有的類加載器都是URLClassLoader的對象~~
    return AccessController.doPrivileged(
            new PrivilegedAction<URLClassLoader>() {
                @Override
                public URLClassLoader run() {
                    if (parent == null)
                        return new URLClassLoader(array);
                    else
                        return new URLClassLoader(array, parent);
                }
            });
}

對 initClassLoaders 分析完,Tomcat 還會進行一項至關重要的安全措施,即 SecurityClassLoad.securityClassLoad 方法。 讓我們深入探究這個方法,看看它在 Tomcat 的安全體系中扮演著怎樣的角色。

public static void securityClassLoad(ClassLoader loader) throws Exception {
    securityClassLoad(loader, true);
}

static void securityClassLoad(ClassLoader loader, boolean requireSecurityManager) throws Exception {

    if (requireSecurityManager && System.getSecurityManager() == null) {
        return;
    }

    loadCorePackage(loader);
    loadCoyotePackage(loader);
    loadLoaderPackage(loader);
    loadRealmPackage(loader);
    loadServletsPackage(loader);
    loadSessionPackage(loader);
    loadUtilPackage(loader);
    loadValvesPackage(loader);
    loadJavaxPackage(loader);
    loadConnectorPackage(loader);
    loadTomcatPackage(loader);
}

 private static final void loadCorePackage(ClassLoader loader) throws Exception {
    final String basePackage = "org.apache.catalina.core.";
    loader.loadClass(basePackage + "AccessLogAdapter");
    loader.loadClass(basePackage + "ApplicationContextFacade$PrivilegedExecuteMethod");
    loader.loadClass(basePackage + "ApplicationDispatcher$PrivilegedForward");
    loader.loadClass(basePackage + "ApplicationDispatcher$PrivilegedInclude");
    loader.loadClass(basePackage + "ApplicationPushBuilder");
    loader.loadClass(basePackage + "AsyncContextImpl");
    loader.loadClass(basePackage + "AsyncContextImpl$AsyncRunnable");
    loader.loadClass(basePackage + "AsyncContextImpl$DebugException");
    loader.loadClass(basePackage + "AsyncListenerWrapper");
    loader.loadClass(basePackage + "ContainerBase$PrivilegedAddChild");
    loadAnonymousInnerClasses(loader, basePackage + "DefaultInstanceManager");
    loader.loadClass(basePackage + "DefaultInstanceManager$AnnotationCacheEntry");
    loader.loadClass(basePackage + "DefaultInstanceManager$AnnotationCacheEntryType");
    loader.loadClass(basePackage + "ApplicationHttpRequest$AttributeNamesEnumerator");
}

這段代碼使用 catalinaLoader 加載了 Tomcat 源代碼中各個專用類,這些類主要分布在以下幾個包中:

  1. org.apache.catalina.core.*
  2. org.apache.coyote.*
  3. org.apache.catalina.loader.*
  4. org.apache.catalina.realm.*
  5. org.apache.catalina.servlets.*
  6. org.apache.catalina.session.*
  7. org.apache.catalina.util.*
  8. org.apache.catalina.valves.*
  9. javax.servlet.http.Cookie
  10. org.apache.catalina.connector.*
  11. org.apache.tomcat.*

至此,我們已經逐一分析了 init 方法中的關鍵方法,包括 initClassLoaders、SecurityClassLoad.securityClassLoad 等,了解了 Tomcat 初始化階段的各個步驟。

WebApp 類加載器

在深入探究 Tomcat 啟動流程的過程中,我們發現似乎遺漏了一個關鍵角色——WebApp 類加載器。

WebApp 類加載器是每個 Web 應用獨有的,而每個 Web 應用本質上就是一個 Context。 因此,我們理所當然地將目光投向了 Context 的實現類。 Tomcat 中,StandardContext 是 Context 的默認實現,而 WebApp 類加載器正是誕生于 StandardContext 類的 startInternal() 方法中。

protected synchronized void startInternal() throws LifecycleException {
    if (getLoader() == null) {
        WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
        webappLoader.setDelegate(getDelegate());
        setLoader(webappLoader);
    }
}

這段代碼的邏輯非常簡潔,它在 WebApp 類加載器不存在的情況下,會創建一個新的 WebApp 類加載器,并將其設置為當前 Context 的加載器(setLoader)。

到這里,我們已經完成了對 Tomcat 啟動過程和類加載機制的全面解析,從 Bootstrap 類開始,一步步深入,最終揭開了 WebApp 類加載器的面紗。

通過這個分析過程,我們不僅了解了 Tomcat 啟動和類加載的具體步驟,更深刻地理解了 Tomcat 采用這種獨特的多層級類加載機制的深層原因,以及這種設計帶來的種種優勢。

責任編輯:武曉燕 來源: 碼上遇見你
相關推薦

2021-01-06 09:01:05

javaclass

2021-07-05 06:51:43

Java機制類加載器

2023-10-31 16:00:51

類加載機制Java

2024-03-12 07:44:53

JVM雙親委托機制類加載器

2017-03-08 10:30:43

JVMJava加載機制

2021-04-29 11:18:14

JVM加載機制

2017-09-20 08:07:32

java加載機制

2025-07-01 07:41:37

Java類加載器雙親委派

2023-10-13 07:29:23

PixiJSRunner

2020-05-26 18:50:46

JVMAttachJava

2024-09-04 09:47:21

2009-02-03 09:42:53

JAVA類JVM指令forName方法

2023-10-17 09:26:44

Java工具

2023-05-10 11:07:18

2020-10-26 11:20:04

jvm類加載Java

2024-12-02 09:01:23

Java虛擬機內存

2020-05-20 22:13:26

JVM加載機制虛擬機

2012-01-18 11:24:18

Java

2022-10-08 08:34:34

JVM加載機制代碼

2023-08-02 08:38:27

JVM加載機制
點贊
收藏

51CTO技術棧公眾號

熟女性饥渴一区二区三区| 国产精品永久免费| 特级西西人体wwwww| 亚洲精品日产| 国产精品私人自拍| 91久久夜色精品国产网站| 欧美 日韩 国产 成人 在线观看| 欧美二三四区| 亚洲丝袜美腿综合| 成人精品一二区| 日韩精品手机在线| 欧美亚洲精品在线| 欧美视频一区二区三区在线观看| 三年中文高清在线观看第6集| 国产高清精品软件丝瓜软件| 一区二区黄色| 色老头一区二区三区在线观看| 欧美激情第四页| 日本不卡网站| 最近中文字幕一区二区三区| 成人欧美一区二区| 亚洲综合图片网| 亚洲自拍偷拍网| 亚洲第一男人天堂| 丝袜制服一区二区三区| h片在线观看网站| 91一区二区在线观看| 成人xxxxx| 久久久国产精品成人免费| 欧美aaaa视频| 亚洲欧美国产精品久久久久久久| 一个色综合久久| 日本黄色免费在线| 一区二区三区日韩| 日本黑人久久| 网站黄在线观看| 国产一区二区三区四区五区入口| 4k岛国日韩精品**专区| 黄色一级大片在线免费观看| 日韩三级视频| 日韩一级欧美一级| 久热精品在线播放| 成人欧美一区二区三区的电影| 国产清纯在线一区二区www| 国产高清在线一区二区| 亚洲天堂视频在线| 噜噜噜躁狠狠躁狠狠精品视频| 九九热这里只有精品6| 成人性生交大片免费看无遮挡aⅴ| 哺乳一区二区三区中文视频| 911精品产国品一二三产区| 免费午夜视频在线观看| 日韩精品av| 亚洲一区二区高清| 一区二区不卡视频| 98在线视频| 久久综合av免费| 国产伦精品一区二区三区四区免费| 国产农村妇女毛片精品久久| 亚洲欧美日韩国产| 91av福利视频| 欧美bbbbbbbbbbbb精品| 亚洲无线一线二线三线区别av| www.午夜精品| 5566中文字幕| 日韩国产欧美| 最近2019年中文视频免费在线观看 | 一区二区三区免费网站| 一区二区三区欧美成人| 国产在线播放av| 久久久久久亚洲综合| 免费一区二区三区| 亚洲 精品 综合 精品 自拍| av午夜一区麻豆| 精品综合在线| 国产又爽又黄网站亚洲视频123| 成人av在线网站| 好吊色欧美一区二区三区视频 | 日韩**一区毛片| 国产成人精品在线视频| 在线观看 亚洲| 美女爽到呻吟久久久久| 日韩免费在线看| 免费观看日批视频| 麻豆91在线观看| 91最新国产视频| 性中国古装videossex| 国产精品一区二区在线观看不卡 | 免费的av在线| 天天干在线视频论坛| 亚洲国产日日夜夜| 国产69精品久久久久久久| 乱人伦视频在线| 色综合久久久久| 久久久91精品| 国产在线高清精品| 中文字幕av网站| 男男成人高潮片免费网站| 欧美在线免费观看| 欧美性猛交xxxx乱大交hd| 蜜臀av性久久久久av蜜臀妖精| 国产精品久久久久福利| 中文字幕在线观看第二页| 久草在线在线精品观看| 国产69精品久久久久9999apgf| 人妻一区二区三区免费| 成人黄页毛片网站| 日韩一区二区三区资源| 2024最新电影免费在线观看| 天涯成人国产亚洲精品一区av| 可以免费在线看黄的网站| 亚洲伦理网站| 欧美精品一区二区三区高清aⅴ | 国产午夜亚洲精品一级在线| 精品黑人一区二区三区久久 | 精品免费囯产一区二区三区| 老司机午夜精品视频| 91久久久久久久一区二区| 亚洲三区在线播放| 亚洲欧美一区二区不卡| 免费欧美一级视频| gogo大尺度成人免费视频| 亚洲第一页在线| 午夜激情福利电影| 国产视频久久| 91精品视频免费观看| 天天摸天天干天天操| 成人欧美一区二区三区1314 | 久久久久久夜| 99九九视频| 爱久久·www| 亚洲444eee在线观看| 午夜剧场在线免费观看| 久久最新网址| 欧美老少配视频| 亚洲天堂手机在线| 久久婷婷国产综合国色天香| 日韩国产小视频| 久久er热在这里只有精品66| 欧美成人精品3d动漫h| 国产又黄又粗的视频| 国产亚洲午夜| 成人免费在线看片| 性欧美1819sex性高清大胸| 欧美日韩国产高清一区二区| 丰腴饱满的极品熟妇| 亚洲毛片网站| 波多野结衣精品久久| 黄色一级片在线观看| 欧美日韩在线三级| 性欧美成人播放77777| 亚洲午夜久久久久久尤物| 亚洲aⅴ男人的天堂在线观看| 91女主播在线观看| 欧美在线一二三| 免费看污片的网站| 亚洲男人影院| 麻豆成人在线播放| 三妻四妾完整版在线观看电视剧| 777午夜精品免费视频| 无码人中文字幕| 天天色影综合网| 日韩激情在线| 日韩av男人的天堂| 毛片在线播放网站| 欧美视频一二三| 我和岳m愉情xxxⅹ视频| 亚洲国产一区二区三区a毛片| 亚洲综合中文字幕在线观看| 国产在线二区| 91精品国产欧美一区二区18| 中文字幕在线观看免费高清| 天堂一区二区在线| 亚洲精品视频一二三| 福利视频一区| 亚洲码在线观看| 一二三区免费视频| 国产日产欧美一区二区三区| 网站一区二区三区| 色婷婷热久久| 亚洲一区二区三| 精品视频在线一区二区| 欧美一区二区黄| 国产一级特黄视频| www欧美成人18+| 日韩有码免费视频| 91九色精品国产一区二区| 91精品国产99久久久久久红楼| 欧美黑人xx片| 日韩毛片中文字幕| 中文字幕第315页| 亚洲美女区一区| 熟女人妻在线视频| 日本中文一区二区三区| 欧洲美女和动交zoz0z| 7777精品| 国产精品成人v| av在线麻豆| 亚洲精品国产精品久久清纯直播| 特级西西444www大胆免费看| 亚洲三级理论片| 久久久午夜精品福利内容| 日韩精品每日更新| 91精品国产毛片武则天| 欧美绝顶高潮抽搐喷水合集| 国产精品精品一区二区三区午夜版 | 亚洲成人午夜电影| 国产毛片久久久久久久| 国产高清成人在线| www.国产区| 欧美亚韩一区| 日韩精品一区二区三区丰满| 久久久久亚洲精品中文字幕| 26uuu国产精品视频| 午夜国产福利在线| 亚洲第一中文字幕| 女人十八岁毛片| 亚洲色图在线视频| 大地资源二中文在线影视观看| 秋霞午夜av一区二区三区| 五月天激情图片| 欧美色图国产精品| 国产在线精品一区| 91精品麻豆| 人九九综合九九宗合| 亚洲精品白浆| 在线观看精品国产视频| 国产 欧美 精品| 91麻豆精品91久久久久同性| 国产一级在线播放| 中文字幕亚洲欧美在线不卡| 美女100%无挡| 国产·精品毛片| 五月婷婷之婷婷| 日韩电影在线免费| 欧美 日本 亚洲| 欧美午夜国产| 熟女熟妇伦久久影院毛片一区二区| 色综合综合色| 精品国产乱码久久久久| **爰片久久毛片| 91九色蝌蚪国产| 成人国产在线| 国产精品成人aaaaa网站| 亚洲精品中文字幕| 91国产视频在线| www555久久| 欧美国产在线视频| 性直播体位视频在线观看| 两个人的视频www国产精品| av成人手机在线| 色综合亚洲精品激情狠狠| 瑟瑟视频在线| 欧美成人性色生活仑片| 天堂va在线| 午夜精品在线观看| 人在线成免费视频| 国产999在线观看| 成人一区视频| 成人免费视频a| 大型av综合网站| 国产一区福利视频| 亚州综合一区| 亚洲乱码国产乱码精品天美传媒| 久久精品国产亚洲夜色av网站 | 欧美一a一片一级一片| 少妇无套内谢久久久久| 欧美高清www午色夜在线视频| 99国产精品99| 亚洲精品二三区| 番号在线播放| 欧美另类老女人| 国内激情视频在线观看| 国产精品久久综合av爱欲tv| 亚洲视频自拍| 国产精品免费一区二区三区在线观看| 亚洲精品动态| 一区二区三区四区国产| 国内精品99| 久久久久久久久久福利| 狠狠网亚洲精品| 野花社区视频在线观看| 国产精品区一区二区三| 青娱乐国产精品| 色88888久久久久久影院野外| 91麻豆国产视频| 亚洲精品福利在线| 免费黄色在线看| 68精品久久久久久欧美| 国产成+人+综合+亚洲欧美| 99在线影院| 欧美亚洲在线日韩| 精品国产av无码一区二区三区| 琪琪一区二区三区| 国产白袜脚足j棉袜在线观看| 中文成人av在线| 激情五月色婷婷| 欧美日韩精品综合在线| 无码国精品一区二区免费蜜桃| 在线观看免费高清视频97| 久久不射影院| 91精品视频大全| 欧美日韩中文字幕一区二区三区| 蜜臀av性久久久久蜜臀av| 久久中文欧美| 一区二区三区少妇| 一区二区三区自拍| 中文字幕日本人妻久久久免费| 精品国产第一区二区三区观看体验| 欧美激情免费| 日本久久久久久| 乱亲女h秽乱长久久久| 最近免费观看高清韩国日本大全| 国产亚洲欧洲| 中国xxxx性xxxx产国| 亚洲丝袜制服诱惑| 亚洲一区二区影视| 亚洲开心激情网| а√天堂中文在线资源8| 91久久久久久久久| 999精品色在线播放| 精品久久久久久无码国产| 成人精品国产免费网站| 国产十六处破外女视频| 在线成人高清不卡| 亚洲麻豆精品| 国产精品久久一区主播| 欧美日韩一二三四| 毛葺葺老太做受视频| 91视频你懂的| 一区二区三区视频免费看| 日韩欧美国产不卡| 牛牛精品在线| 69堂成人精品视频免费| 亚洲一本二本| 无码国产精品一区二区高潮| 亚洲欧美视频在线观看视频| 亚洲中文一区二区三区| 日日骚久久av| 国产综合色在线观看| 亚洲高清123| 另类欧美日韩国产在线| 日本污视频网站| 精品污污网站免费看| 福利在线播放| 91精品久久久久久久久久久| 久久国产电影| xxx中文字幕| 亚洲一区二区精品3399| 欧美熟妇另类久久久久久不卡 | 伊人久久免费视频| 中文字幕系列一区| 三区精品视频观看| 久久丁香综合五月国产三级网站 | 91综合久久一区二区| 一本一道久久a久久综合蜜桃| 亚洲欧洲精品一区二区精品久久久| 成人免费一区二区三区| www.欧美免费| 亚洲一区二区电影| 乱妇乱女熟妇熟女网站| 国产欧美精品一区二区色综合朱莉| 亚洲成人av网址| 久久这里只有精品视频首页| 日韩影片在线观看| 18禁免费无码无遮挡不卡网站| 久久亚洲综合av| 亚洲一级片免费看| 久久99久久99精品中文字幕| 精品三级av| 国产理论在线播放| 亚洲日本在线天堂| 亚洲欧美一区二区三| 国产成人在线一区二区| 91精品啪在线观看国产18| 在线播放第一页| 91福利国产精品| 污片视频在线免费观看| 久久偷看各类wc女厕嘘嘘偷窃| 蜜臀av在线播放一区二区三区| 国产少妇在线观看| 亚洲免费av片| 97久久精品一区二区三区的观看方式| 天天做天天躁天天躁| 久久久精品免费网站| 国产日韩免费视频| 68精品久久久久久欧美| 91日韩欧美| 欧美xxxxx精品| 欧美日韩成人综合| yellow在线观看网址| 一区二区冒白浆视频| 99久久婷婷国产| 91tv国产成人福利| 亚州精品天堂中文字幕| 99精品视频在线观看播放| 国产精品久久久久久亚洲色| 欧美体内she精视频| 美女搞黄视频在线观看| 综合国产精品久久久|