<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Java究竟怎么玩?

      天地程序已定棋,人間大數(shù)待變局

        博客園  :: 首頁  :: 新隨筆  :: 聯(lián)系 :: 訂閱 訂閱  :: 管理
      對于許多關(guān)鍵性業(yè)務或者龐大的 Java 系統(tǒng)來說,如果必須暫停系統(tǒng)服務才能進行系統(tǒng)升級,既會大大影響到系統(tǒng)的可用性,同時也增加了系統(tǒng)的管理和維護成本。因此,如果能夠方便地在不停止系統(tǒng)業(yè) 務的情況下進行系統(tǒng)升級,則可以很好地解決上述問題。在本文中,我們將基于實例,對構(gòu)建在線升級 Java 系統(tǒng)的基礎(chǔ)技術(shù)和設(shè)計原則進行了深入的講解。相信讀者能夠根據(jù)文中的技術(shù)構(gòu)建出自己的在線升級系統(tǒng)來。

      Java ClassLoader 技術(shù)剖析

      在本文中,我們將不對 Java ClassLoader 的細節(jié)進行過于詳細的講解,而是關(guān)注于和構(gòu)建在線升級系統(tǒng)相關(guān)的基礎(chǔ)概念。關(guān)于 ClassLoader 的詳細細節(jié)許多資料可以參考,有興趣的讀者可以自行研讀。

      要構(gòu)建在線升級系統(tǒng),一個重要的技術(shù)就是能夠?qū)崿F(xiàn) Java 類的熱替換 —— 也就是在不停止正在運行的系統(tǒng)的情況下進行類(對象)的升級替換。而 Java 的 ClassLoader 正是實現(xiàn)這項技術(shù)的基礎(chǔ)。

      在 Java 中,類的實例化流程分為兩個部分:類的加載和類的實例化。類的加載又分為顯式加載和隱式加載。大家使用 new 關(guān)鍵字創(chuàng)建類實例時,其實就隱式地包含了類的加載過程。對于類的顯式加載來說,比較常用的是 Class.forName。其實,它們都是通過調(diào)用 ClassLoader 類的 loadClass 方法來完成類的實際加載工作的。直接調(diào)用 ClassLoader 的 loadClass 方法是另外一種不常用的顯式加載類的技術(shù)。


      圖 1. Java 類加載器層次結(jié)構(gòu)圖
      Java 類加載器層次結(jié)構(gòu)圖

      ClassLoader 在加載類時有一定的層次關(guān)系和規(guī)則。在 Java 中,有四種類型的類加載器,分別為:BootStrapClassLoader、ExtClassLoader、AppClassLoader 以及用戶自定義的 ClassLoader。這四種類加載器分別負責不同路徑的類的加載,并形成了一個類加載的層次結(jié)構(gòu)。

      BootStrapClassLoader 處于類加載器層次結(jié)構(gòu)的最高層,負責 sun.boot.class.path 路徑下類的加載,默認為 jre/lib 目錄下的核心 API 或 -Xbootclasspath 選項指定的 jar 包。ExtClassLoader 的加載路徑為 java.ext.dirs,默認為 jre/lib/ext 目錄或者 -Djava.ext.dirs 指定目錄下的 jar 包加載。AppClassLoader 的加載路徑為 java.class.path,默認為環(huán)境變量 CLASSPATH 中設(shè)定的值。也可以通過 -classpath 選型進行指定。用戶自定義 ClassLoader 可以根據(jù)用戶的需要定制自己的類加載過程,在運行期進行指定類的動態(tài)實時加載。

      這四種類加載器的層次關(guān)系圖如 圖 1 所示。一般來說,這四種類加載器會形成一種父子關(guān)系,高層為低層的父加載器。在進行類加載時,首先會自底向上挨個檢查是否已經(jīng)加載了指定類,如果已經(jīng)加載 則直接返回該類的引用。如果到最高層也沒有加載過指定類,那么會自頂向下挨個嘗試加載,直到用戶自定義類加載器,如果還不能成功,就會拋出異常。Java 類的加載過程如 圖 2 所示。


      圖 2. Java 類的加載過程
      圖 2. Java 類的加載過程

      每個類加載器有自己的名字空間,對于同一個類加載器實例來說,名字相同的類只能存在一個,并且僅加載一次。不管該類有沒有變化,下次再需要加載時,它只是從自己的緩存中直接返回已經(jīng)加載過的類引用。

      我 們編寫的應用類默認情況下都是通過 AppClassLoader 進行加載的。當我們使用 new 關(guān)鍵字或者 Class.forName 來加載類時,所要加載的類都是由調(diào)用 new 或者 Class.forName 的類的類加載器(也是 AppClassLoader)進行加載的。要想實現(xiàn) Java 類的熱替換,首先必須要實現(xiàn)系統(tǒng)中同名類的不同版本實例的共存,通過上面的介紹我們知道,要想實現(xiàn)同一個類的不同版本的共存,我們必須要通過不同的類加載 器來加載該類的不同版本。另外,為了能夠繞過 Java 類的既定加載過程,我們需要實現(xiàn)自己的類加載器,并在其中對類的加載過程進行完全的控制和管理。

       

      編寫自定義的 ClassLoader

      為了能夠完全掌控類的加載過程,我們的定制類加載器需要直接從 ClassLoader 繼承。首先我們來介紹一下 ClassLoader 類中和熱替換有關(guān)的的一些重要方法。

      • findLoadedClass: 每 個類加載器都維護有自己的一份已加載類名字空間,其中不能出現(xiàn)兩個同名的類。凡是通過該類加載器加載的類,無論是直接的還是間接的,都保存在自己的名字空 間中,該方法就是在該名字空間中尋找指定的類是否已存在,如果存在就返回給類的引用,否則就返回 null。這里的直接是指,存在于該類加載器的加載路徑上并由該加載器完成加載,間接是指,由該類加載器把類的加載工作委托給其他類加載器完成類的實際加 載。
      • getSystemClassLoader Java2 中新增的方法。該方法返回系統(tǒng)使用的 ClassLoader。可以在自己定制的類加載器中通過該方法把一部分工作轉(zhuǎn)交給系統(tǒng)類加載器去處理。
      • defineClass: 該方法是 ClassLoader 中非常重要的一個方法,它接收以字節(jié)數(shù)組表示的類字節(jié)碼,并把它轉(zhuǎn)換成 Class 實例,該方法轉(zhuǎn)換一個類的同時,會先要求裝載該類的父類以及實現(xiàn)的接口類。
      • loadClass: 加載類的入口方法,調(diào)用該方法完成類的顯式加載。通過對該方法的重新實現(xiàn),我們可以完全控制和管理類的加載過程。
      • resolveClass: 鏈接一個指定的類。這是一個在某些情況下確保類可用的必要方法,詳見 Java 語言規(guī)范中“執(zhí)行”一章對該方法的描述。

      了解了上面的這些方法,下面我們來實現(xiàn)一個定制的類加載器來完成這樣的加載流程:我們?yōu)樵擃惣虞d器指定一些必須由該類加載器直接加載的類集合,在該類加載器 進行類的加載時,如果要加載的類屬于必須由該類加載器加載的集合,那么就由它直接來完成類的加載,否則就把類加載的工作委托給系統(tǒng)的類加載器完成。

      在 給出示例代碼前,有兩點內(nèi)容需要說明一下:1、要想實現(xiàn)同一個類的不同版本的共存,那么這些不同版本必須由不同的類加載器進行加載,因此就不能把這些類的 加載工作委托給系統(tǒng)加載器來完成,因為它們只有一份。2、為了做到這一點,就不能采用系統(tǒng)默認的類加載器委托規(guī)則,也就是說我們定制的類加載器的父加載器 必須設(shè)置為 null。該定制的類加載器的實現(xiàn)代碼如下:

       

      class CustomCL extends ClassLoader { 

      private String basedir; // 需要該類加載器直接加載的類文件的基目錄
      private HashSet dynaclazns; // 需要由該類加載器直接加載的類名

      public CustomCL(String basedir, String[] clazns) {
      super(null); // 指定父類加載器為 null
      this.basedir = basedir;
      dynaclazns = new HashSet();
      loadClassByMe(clazns);
      }

      private void loadClassByMe(String[] clazns) {
      for (int i = 0; i < clazns.length; i++) {
      loadDirectly(clazns[i]);
      dynaclazns.add(clazns[i]);
      }
      }

      private Class loadDirectly(String name) {
      Class cls = null;
      StringBuffer sb = new StringBuffer(basedir);
      String classname = name.replace('.', File.separatorChar) + ".class";
      sb.append(File.separator + classname);
      File classF = new File(sb.toString());
      cls = instantiateClass(name,new FileInputStream(classF),
      classF.length());
      return cls;
      }

      private Class instantiateClass(String name,InputStream fin,long len){
      byte[] raw = new byte[(int) len];
      fin.read(raw);
      fin.close();
      return defineClass(name,raw,0,raw.length);
      }

      protected Class loadClass(String name, boolean resolve)
      throws ClassNotFoundException {
      Class cls = null;
      cls = findLoadedClass(name);
      if(!this.dynaclazns.contains(name) && cls == null)
      cls = getSystemClassLoader().loadClass(name);
      if (cls == null)
      throw new ClassNotFoundException(name);
      if (resolve)
      resolveClass(cls);
      return cls;
      }

      }

       

      在該類加載器的實現(xiàn)中,所有指定必須由它直接加載的類都在該 加載器實例化時進行了加載,當通過 loadClass 進行類的加載時,如果該類沒有加載過,并且不屬于必須由該類加載器加載之列都委托給系統(tǒng)加載器進行加載。理解了這個實現(xiàn),距離實現(xiàn)類的熱替換就只有一步之 遙了,我們在下一小節(jié)對此進行詳細的講解

       

      實現(xiàn) Java 類的熱替換

      在本小節(jié)中,我們將結(jié)合前面講述的類加載器的特性,并在上小節(jié)實現(xiàn)的自定義類加載器的基礎(chǔ)上實現(xiàn) Java 類的熱替換。首先我們把上小節(jié)中實現(xiàn)的類加載器的類名 CustomCL 更改為 HotswapCL,以明確表達我們的意圖。

      現(xiàn)在來介紹一下我們的實驗方法,為了簡單起見,我們的包為默認包,沒有層次,并且省去了所有錯誤處理。要替換的類為 Foo,實現(xiàn)很簡單,僅包含一個方法 sayHello:


      清單 2. 待替換的示例類

       

      public class Foo{ 
      public void sayHello() {
      System.out.println("hello world! (version one)");
      }
      }

       

      在當前工作目錄下建立一個新的目錄 swap,把編譯好的 Foo.class 文件放在該目錄中。接下來要使用我們前面編寫的 HotswapCL 來實現(xiàn)該類的熱替換。具體的做法為:我們編寫一個定時器任務,每隔 2 秒鐘執(zhí)行一次。其中,我們會創(chuàng)建新的類加載器實例加載 Foo 類,生成實例,并調(diào)用 sayHello 方法。接下來,我們會修改 Foo 類中 sayHello 方法的打印內(nèi)容,重新編譯,并在系統(tǒng)運行的情況下替換掉原來的 Foo.class,我們會看到系統(tǒng)會打印出更改后的內(nèi)容。定時任務的實現(xiàn)如下(其它代碼省略,請讀者自行補齊):

       

      public void run(){ 
      try {
      // 每次都創(chuàng)建出一個新的類加載器
      HowswapCL cl = new HowswapCL("../swap", new String[]{"Foo"});
      Class cls = cl.loadClass("Foo");
      Object foo = cls.newInstance();

      Method m = foo.getClass().getMethod("sayHello", new Class[]{});
      m.invoke(foo, new Object[]{});

      } catch(Exception ex) {
      ex.printStackTrace();
      }
      }

       

      編譯、運行我們的系統(tǒng),會出現(xiàn)如下的打印:


      圖 3. 熱替換前的運行結(jié)果
      圖 3. 熱替換前的運行結(jié)果

      好,現(xiàn)在我們把 Foo 類的 sayHello 方法更改為:

      public void sayHello() { 
      System.out.println("hello world! (version two)");
      }

       

      在系統(tǒng)仍在運行的情況下,編譯,并替換掉 swap 目錄下原來的 Foo.class 文件,我們再看看屏幕的打印,奇妙的事情發(fā)生了,新更改的類在線即時生效了,我們已經(jīng)實現(xiàn)了 Foo 類的熱替換。屏幕打印如下:


      圖 4. 熱替換后的運行結(jié)果
      圖 4. 熱替換后的運行結(jié)果

      敏銳的讀者可能會問,為何不用把 foo 轉(zhuǎn)型為 Foo,直接調(diào)用其 sayHello 方法呢?這樣不是更清晰明了嗎?下面我們來解釋一下原因,并給出一種更好的方法。

      如果我們采用轉(zhuǎn)型的方法,代碼會變成這樣:Foo foo = (Foo)cls.newInstance(); 讀者如果跟隨本文進行試驗的話,會發(fā)現(xiàn)這句話會拋出 ClassCastException 異常,為什么嗎?因為在 Java 中,即使是同一個類文件,如果是由不同的類加載器實例加載的,那么它們的類型是不相同的。在上面的例子中 cls 是由 HowswapCL 加載的,而 foo 變量類型聲名和轉(zhuǎn)型里的 Foo 類卻是由 run 方法所屬的類的加載器(默認為 AppClassLoader)加載的,因此是完全不同的類型,所以會拋出轉(zhuǎn)型異常。

      那么通過接口調(diào)用是不是就行了呢?我們可以定義一個 IFoo 接口,其中聲名 sayHello 方法,F(xiàn)oo 實現(xiàn)該接口。也就是這樣:IFoo foo = (IFoo)cls.newInstance(); 本來該方法也會有同樣的問題的,因為外部聲名和轉(zhuǎn)型部分的 IFoo 是由 run 方法所屬的類加載器加載的,而 Foo 類定義中 implements IFoo 中的 IFoo 是由 HotswapCL 加載的,因此屬于不同的類型轉(zhuǎn)型還是會拋出異常的,但是由于我們在實例化 HotswapCL 時是這樣的:

      HowswapCL cl = new HowswapCL("../swap", new String[]{"Foo"});

      其中僅僅指定 Foo 類由 HotswapCL 加載,而其實現(xiàn)的 IFoo 接口文件會委托給系統(tǒng)類加載器加載,因此轉(zhuǎn)型成功,采用接口調(diào)用的代碼如下:


      清單 4. 采用接口調(diào)用的代碼

       

      public void run(){ 
      try {
      HowswapCL cl = new HowswapCL("../swap", new String[]{"Foo"});
      Class cls = cl.loadClass("Foo");
      IFoo foo = (IFoo)cls.newInstance();
      foo.sayHello();
      } catch(Exception ex) {
      ex.printStackTrace();
      }
      }

      確實,簡潔明了了很多。在我們的實驗中,每當定時器調(diào)度到 run 方法時,我們都會創(chuàng)建一個新的 HotswapCL 實例,在產(chǎn)品代碼中,無需如此,僅當需要升級替換時才去創(chuàng)建一個新的類加載器實例。

       

      在線升級系統(tǒng)的設(shè)計原則

      在 上小節(jié)中,我們給出了一個 Java 類熱替換的實例,掌握了這項技術(shù),就具備了實現(xiàn)在線升級系統(tǒng)的基礎(chǔ)。但是,對于一個真正的產(chǎn)品系統(tǒng)來說,升級本省就是一項非常復雜的工程,如果要在線升 級,就會更加復雜。其中,實現(xiàn)類的熱替換只是最后一步操作,在線升級的要求會對系統(tǒng)的整體設(shè)計帶來深遠的影響。下面我們來談談在線升級系統(tǒng)設(shè)計方面的一些 原則:

      • 在系統(tǒng)設(shè)計一開始,就要考慮系統(tǒng)的哪些部分是需要以后在線升級的,哪些部分是穩(wěn)定的。

        雖然我們可以把系統(tǒng)設(shè)計成任何一部分都是可以在線升級的,但是其成本是非常高昂的,也沒有必要。因此,明確地界定出系統(tǒng)以后需要在線升級的部分是明智之舉。這些部分常常是系統(tǒng)業(yè)務邏輯規(guī)則、算法等等。

      • 設(shè)計出規(guī)范一致的系統(tǒng)狀態(tài)轉(zhuǎn)換方法。

        替換一個類僅僅是在線升級系統(tǒng)所要做的工作中的一個步驟,為了使系統(tǒng)能夠在升級后正常運行,就必須保持升級前后系統(tǒng)狀態(tài)的一致性。因此,在設(shè)計時要考慮需要在線升級的部分所涉及的系統(tǒng)狀態(tài)有哪些,把這些狀態(tài)設(shè)計成便于獲取、設(shè)置和轉(zhuǎn)換的,并用一致的方式來進行。

      • 明確出系統(tǒng)的升級控制協(xié)議。

        這 個原則是關(guān)于系統(tǒng)在線升級的時機和流程控制的,不考慮系統(tǒng)的當前運行狀態(tài)就貿(mào)然進行升級是一項非常危險的活動。因此在系統(tǒng)設(shè)計中, 就要考慮并預留出系統(tǒng)在線升級的控制點, 并定義清晰、明確的升級協(xié)議來協(xié)調(diào)、控制多個升級實體的升級次序,以確保系統(tǒng)在升級的任何時刻都處在一個確定的狀態(tài)下。

      • 考慮到升級失敗時的回退機制。

        即使我們做了非常縝密細致的設(shè)計,還是難以從根本上保證系統(tǒng)升級一定是成功的,對于大型分布式系統(tǒng)來說尤其如此。因此在系統(tǒng)設(shè)計時,要考慮升級失敗后的回退機制。

      好了,本小節(jié)我們簡單介紹了在線升級系統(tǒng)設(shè)計時的幾個重要的原則,下一小節(jié)我們將給出一個簡單的實例,來演示一下如何來實現(xiàn)一個在線升級系統(tǒng)。

      在線升級系統(tǒng)實例


      首先,我們來簡單介紹一下這個實例的結(jié)構(gòu)組成和要完成的工作。在我們的例子中,主要有三個實體,一個是升級控制實體,兩個是工作實體,都基于 ActiveObject 實現(xiàn)。

      升級控制實體以 RMI 的方式對外提供了一個管理命令接口,用以接收外部的在線升級命令。工作實體有兩個消息隊列,一個用以接收分配給它的任務(我們用定時器定時給它發(fā)送任務命 令消息),我們稱其為任務隊列;另一個用于和升級控制實體交互,協(xié)作完成升級過程,我們稱其為控制隊列。工作實體中的任務很簡單,就是使用我們前面介紹的 Foo 類簡單地打印出一個字符串,不過這次字符串作為狀態(tài)保存在工作實體中,動態(tài)設(shè)置給 Foo 類的實例的。升級的協(xié)議流程如下:

      當 升級控制實體接收到來自 RMI 的在線升級命令時,它會向兩個工作實體的任務隊列中發(fā)送一條準備升級消息,然后等待回應。當工作實體在任務隊列中收到準備升級消息時,會立即給升級控制實 體發(fā)送一條準備就緒消息,然后切換到控制隊列等待進一步的升級指令。升級控制實體收齊這兩個工作實體發(fā)來的準備就緒消息后,就給這兩個工作實體的控制隊列 各發(fā)送一條開始升級消息,然后等待結(jié)果。工作實體收到開始升級消息后,進行實際的升級工作,也就是我們前面講述的熱替換類。然后,給升級控制實體發(fā)送升級 完畢消息。升級控制實體收到來自兩個工作實體的升級完畢消息后,會給這兩個工作實體的控制隊列各發(fā)送一條繼續(xù)工作消息,工作實體收到繼續(xù)工作消息后,切換 到任務隊列繼續(xù)工作。升級過程結(jié)束。

      主要的代碼片段如下(略去命令消息的定義和執(zhí)行細節(jié)):


      清單 5. 主要的代碼片段

       

      // 升級控制實體關(guān)鍵代碼
      class UpgradeController extends ActiveObject{
      int nready = 0;
      int nfinished = 0;
      Worker[] workers;
      ......
      // 收到外部升級命令消息時,會觸發(fā)該方法被調(diào)用
      public void askForUpgrade() {
      for(int i=0; i<workers.length; i++)
      workers[i].getTaskQueue().enqueue(new PrepareUpgradeCmd(workers[i]));
      }

      // 收到工作實體回應的準備就緒命令消息時,會觸發(fā)該方法被調(diào)用
      public void readyForUpgrade(String worker_name) {
      nready++;
      if(nready == workers.length){
      for(int i=0; i<workers.length; i++)
      workers[i].getControlQueue().enqueue(new
      StartUpgradeCmd(workers[i]));
      }
      }

      // 收到工作實體回應的升級完畢命令消息時,會觸發(fā)該方法被調(diào)用
      public void finishUpgrade(String worker_name) {
      nfinished++;
      if(nfinished == workers.length){
      for(int i=0; i<workers.length; i++)
      workers[i].getControlQueue().enqueue(new
      ContineWorkCmd(workers[i]));

      }
      }

      ......

      }

      // 工作實體關(guān)鍵代碼
      class Worker extends ActiveObject{
      UpgradeController ugc;
      HotswapCL hscl;
      IFoo foo;
      String state = "hello world!";

      ......

      // 收到升級控制實體的準備升級命令消息時,會觸發(fā)該方法被調(diào)用
      public void prepareUpgrade() {
      switchToControlQueue();
      ugc.getMsgQueue().enqueue(new ReadyForUpdateCMD(ugc,this));
      }

      // 收到升級控制實體的開始升級命令消息時,會觸發(fā)該方法被調(diào)用
      public void startUpgrade(String worker_name) {
      doUpgrade();
      ugc.getMsgQueue().enqueue(new FinishUpgradeCMD(ugc,this));
      }

      // 收到升級控制實體的繼續(xù)工作命令消息時,會觸發(fā)該方法被調(diào)用
      public void continueWork(String worker_name) {
      switchToTaskQueue();
      }

      // 收到定時命令消息時,會觸發(fā)該方法被調(diào)用
      public void doWork() {
      foo.sayHello();
      }

      // 實際升級動作
      private void doUpgrade() {
      hscl = new HowswapCL("../swap", new String[]{"Foo"});
      Class cls = hscl.loadClass("Foo");
      foo = (IFoo)cls.newInstance();
      foo.SetState(state);
      }
      }

      //IFoo 接口定義
      interface IFoo {
      void SetState(String);
      void sayHello();
      }

       

      在Foo 類第一個版本的實現(xiàn)中,只是把設(shè)置進來的字符串直接打印出來。在第二個版本中,會先把設(shè)置進來的字符串變?yōu)榇髮懀缓蟠蛴〕鰜怼@雍芎唵危荚诒磉_規(guī)則 或者算法方面的升級變化。另外,我們并沒有提及諸如:消息超時、升級失敗等方面的異常情況,這在實際產(chǎn)品開發(fā)中是必須要考慮的。

       

      在本文中,我們對 Java 在線升級系統(tǒng)中設(shè)計的基礎(chǔ)技術(shù):類的熱替換,進行了詳細的講解。此外,還給出了在線升級系統(tǒng)設(shè)計時的一些主要指導原則。為了使讀者更好地理解這些技術(shù)和原 則,我們在最后給出了一個在線升級系統(tǒng)的實例。值得注意的是,構(gòu)建在線升級系統(tǒng)不僅僅是一個技術(shù)問題,還牽扯到很多管理方面的因素,比如:如何管理、部署 系統(tǒng)中的可在線升級部分和不可在線升級部分以降低系統(tǒng)的管理、維護成本等。希望本文在讀者構(gòu)建自己的在線升級系統(tǒng)時能夠提供一些幫助。

       

      posted on 2010-01-15 23:34  cping  閱讀(215)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产成人精彩在线视频| 日韩精品区一区二区三vr| 少妇xxxxx性开放| 双乳奶水饱满少妇呻吟免费看| 亚洲无线码一区二区三区| 亚洲精品美女一区二区| 天堂V亚洲国产V第一次| 久久天天躁狠狠躁夜夜avapp| 野外少妇被弄到喷水在线观看| 国产99精品成人午夜在线| www成人国产高清内射| 国产一二三四区中| 丰腴饱满的极品熟妇| 果冻传媒一区二区天美传媒| 久久综合88熟人妻| 91亚洲国产成人精品福利| 亚洲av男人电影天堂热app| 少妇xxxxx性开放| av中文无码乱人伦在线观看| 亚洲性夜夜天天天| 久久zyz资源站无码中文动漫| 人妻丰满熟妇无码区免费| 亚洲特黄色片一区二区三区| 中文字幕理伦午夜福利片| 天堂V亚洲国产V第一次| 亚洲天堂成人网在线观看| 国产一区二区三区不卡在线看| 麻豆蜜桃伦理一区二区三区| 亚洲天堂成年人在线视频| 中文字幕人妻不卡精品| 狠狠干| 国产精品多p对白交换绿帽| 18国产午夜福利一二区| 婷婷国产成人精品视频| 视频一区二区三区四区五区| 繁昌县| 欧美大胆老熟妇乱子伦视频| 日本一区不卡高清更新二区| 亚洲中文字幕无码一区无广告| 东京热大乱系列无码| 欧美视频网站www色|