国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Java中怎么實(shí)現日志緩存機制

發(fā)布時(shí)間:2021-07-04 20:13 來(lái)源:億速云 閱讀:0 作者:Leah 欄目: 開(kāi)發(fā)技術(shù)

今天就跟大家聊聊有關(guān)Java中怎么實(shí)現日志緩存機制,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

Java 日志機制的介紹

Java 日志機制在很多文章中都有介紹,為了便于后面文章部分的理解,在這里再簡(jiǎn)單介紹一下本文用到的一些關(guān)鍵字。

Level:JDK 中定義了 Off、Severe、Warning、Info、Config、Fine、Finer、Finest、All  九個(gè)日志級別,定義 Off 為日志***等級,All  為***等級。每條日志必須對應一個(gè)級別。級別的定義主要用來(lái)對日志的嚴重程度進(jìn)行分類(lèi),同時(shí)可以用于控制日志是否輸出。

LogRecord:每一條日志會(huì )被記錄為一條 LogRecord, 其中存儲了類(lèi)名、方法名、線(xiàn)程 ID、打印的消息等等一些信息。

Logger:日志結構的基本單元。Logger 是以樹(shù)形結構存儲在內存中的,根節點(diǎn)為 root。com.test(如果存在)一定是  com.test.demo(如果存在)的父節點(diǎn),即前綴匹配的已存在的 logger 一定是這個(gè) logger  的父節點(diǎn)。這種父子關(guān)系的定義,可以為用戶(hù)提供更為自由的控制粒度。因為子節點(diǎn)中如果沒(méi)有定義處理規則,如級別 handler、formatter  等,那么默認就會(huì )使用父節點(diǎn)中的這些處理規則。

Handler:用來(lái)處理 LogRecord,默認 Handler 是可以連接成一個(gè)鏈狀,依次對 LogRecord 進(jìn)行處理。

Filter:日志過(guò)濾器。在 JDK 中,沒(méi)有實(shí)現。

Formatter:它主要用于定義一個(gè) LogRecord 的輸出格式。

圖 1. Java 日志處理流程

圖 1 展示了一個(gè) LogRecord 的處理流程。一條日志進(jìn)入處理流程首先是 Logger,其中定義了可通過(guò)的 Level,如果  LogRecord 的 Level 高于Logger 的等級,則進(jìn)入 Filter(如果有)過(guò)濾。如果沒(méi)有定義 Level,則使用父  Logger 的 Level。Handler 中過(guò)程類(lèi)似,其中 Handler 也定義了可通過(guò) Level,然后進(jìn)行 Filter  過(guò)濾,通過(guò)如果后面還有其他 Handler,則直接交由后面的 Handler 進(jìn)行處理,否則會(huì )直接綁定到 formatter  上面輸出到指定位置。

在實(shí)現日志緩存之前,先對 Filter 和 Formatter 兩個(gè)輔助類(lèi)進(jìn)行介紹。

Filter

Filter 是一個(gè)接口,主要是對 LogRecord 進(jìn)行過(guò)濾,控制是否對 LogRecord 進(jìn)行進(jìn)一步處理,其可以綁定在 Logger 下或 Handler 下。

只要在 boolean isLoggable(LogRecord)方法中加上過(guò)濾邏輯就可以實(shí)現對 logrecord  進(jìn)行控制,如果只想對發(fā)生了 Exception 的那些 log 記錄進(jìn)行記錄,那么可以通過(guò)清單 1 來(lái)實(shí)現,當然首先需要將該 Filter  通過(guò)調用 setFilter(Filter)方法或者配置文件方式綁定到對應的 Logger 或 Handler。

清單 1. 一個(gè) Filter 實(shí)例的實(shí)現

Override  public boolean isLoggable(LogRecord record){  if(record.getThrown()!=null){         return true;  }else{          return false;   }  }

Formatter

Formatter 主要是對 Handler 在輸出 log 記錄的格式進(jìn)行控制,比如輸出日期的格式,輸出為 HTML 還是 XML  格式,文本參數替換等。Formatter 可以綁定到 Handler 上,Handler 會(huì )自動(dòng)調用 Formatter 的 String  format(LogRecord r) 方法對日志記錄進(jìn)行格式化,該方法具有默認的實(shí)現,如果想實(shí)現自定義格式可以繼承 Formater  類(lèi)并重寫(xiě)該方法,默認情況下例如清單 2 在經(jīng)過(guò) Formatter 格式化后,會(huì )將 {0} 和 {1} 替換成對應的參數。

清單 2. 記錄一條 log

logger.log(Level.WARNING,"this log is for test1: {0} and test2:{1}",     new Object[]{newTest1(),     new Test2()});

MemoryHandler

MemoryHandler 是 Java Logging 中兩大類(lèi) Handler 之一,另一類(lèi)是  StreamHandler,二者直接繼承于 Handler,代表了兩種不同的設計思路。Java Logging Handler  是一個(gè)抽象類(lèi),需要根據使用場(chǎng)景創(chuàng )建具體 Handler,實(shí)現各自的 publish、flush 以及 close 等方法。

MemoryHandler 使用了典型的“注冊 – 通知”的觀(guān)察者模式。MemoryHandler 先注冊到對自己感興趣的 Logger  中(logger.addHandler(handler)),在這些 Logger 調用發(fā)布日志的  API:log()、logp()、logrb() 等,遍歷這些 Logger 下綁定的所有 Handlers 時(shí),通知觸發(fā)自身  publish(LogRecord)方法的調用,將日志寫(xiě)入 buffer,當轉儲到下一個(gè)日志發(fā)布平臺的條件成立,轉儲日志并清空 buffer。

這里的 buffer 是 MemoryHandler 自身維護一個(gè)可自定義大小的循環(huán)緩沖隊列,來(lái)保存所有運行時(shí)觸發(fā)的 Exception  日志條目。同時(shí)在構造函數中要求指定一個(gè) Target Handler,用于承接輸出;在滿(mǎn)足特定 flush buffer  的條件下,如日志條目等級高于 MemoryHandler 設定的 push level 等級(實(shí)例中定義為  SEVERE)等,將日志移交至下一步輸出平臺。從而形成如下日志轉儲輸出鏈:

圖 2. Log 轉儲鏈

在實(shí)例中,通過(guò)對 MemoryHandler 配置項 .push 的 Level 進(jìn)行判斷,決定是否將日志推向下一個(gè) Handler,通常在 publish() 方法內實(shí)現。代碼清單如下:

清單 3

// 只紀錄有異常并且高于 pushLevel 的 logRecord     final Level level = record.getLevel();            final Throwable thrown = record.getThrown();     If(level >= pushLevel){        push();     }

MemoryHandler.push 方法的觸發(fā)條件

Push 方法會(huì )導致 MemoryHandler 轉儲日志到下一 handler,清空 buffer。觸發(fā)條件可以是但不局限于以下幾種,實(shí)例中使用的是默認的***種:

  • 日志條目的 Level 大于或等于當前 MemoryHandler 中默認定義或用戶(hù)配置的 pushLevel;

  • 外部程序調用 MemoryHandler 的 push 方法;

  • MemoryHandler 子類(lèi)可以重載 log 方法或自定義觸發(fā)方法,在方法中逐一掃描日志條目,滿(mǎn)足自定義規則則觸發(fā)轉儲日志和清空 buffer 的操作。MemoryHanadler 的可配置屬性

表 1.MemoryHandler 可配置屬性

使用方式:

以上是記錄產(chǎn)品 Exception 錯誤日志,以及如何轉儲的 MemoryHandler 處理的內部細節;接下來(lái)給出 MemoryHandler 的一些使用方式。

1. 直接使用 java.util.logging 中的 MemoryHandler

清單4

// 在 buffer 中維護 5 條日志信息 // 僅記錄 Level 大于等于 Warning 的日志條目并 // 刷新 buffer 中的日志條目到 fileHandler 中處理          int bufferSize = 5;          f = new FileHandler("testMemoryHandler.log");          m = new MemoryHandler(f, bufferSize, Level.WARNING);          …          myLogger = Logger.getLogger("com.ibm.test");          myLogger.addHandler(m);          myLogger.log(Level.WARNING, “this is a WARNING log”);

. 自定義

1)反射

思考自定義 MyHandler 繼承自 MemoryHandler 的場(chǎng)景,由于無(wú)法直接使用作為父類(lèi)私有屬性的 size、buffer 及  buffer 中的 cursor,如果在 MyHandler 中有獲取和改變這些屬性的需求,一個(gè)途徑是使用反射。清單 5  展示了使用反射讀取用戶(hù)配置并設置私有屬性。

清單5

int m_size;   String sizeString = manager.getProperty(loggerName + ".size");   if (null != sizeString) {          try {           m_size = Integer.parseInt(sizeString);           if (m_size <= 0) {              m_size = BUFFER_SIZE; // default 1000           }  // 通過(guò) java 反射機制獲取私有屬性           Field f;           f = getClass().getSuperclass().getDeclaredField("size");           f.setAccessible(true);           f.setInt(this, m_size);           f = getClass().getSuperclass().getDeclaredField("buffer");           f.setAccessible(true);           f.set(this, new LogRecord[m_size]);          } catch (Exception e) {          }   }

2)重寫(xiě)

直接使用反射方便快捷,適用于對父類(lèi)私有屬性無(wú)頻繁訪(fǎng)問(wèn)的場(chǎng)景。思考這樣一種場(chǎng)景,默認環(huán)形隊列無(wú)法滿(mǎn)足我們存儲需求,此時(shí)不妨令自定義的 MyMemoryHandler 直接繼承 Handler,直接對存儲結構進(jìn)行操作,可以通過(guò)清單 6 實(shí)現。

清單 6

public class MyMemoryHandler extends Handler{   // 默認存儲 LogRecord 的緩沖區容量   private static final int DEFAULT_SIZE = 1000;   // 設置緩沖區大小   private int size = DEFAULT_SIZE;   // 設置緩沖區   private LogRecord[] buffer;   // 參考 java.util.logging.MemoryHandler 實(shí)現其它部分   ...  }

使用 MemoryHandler 時(shí)需關(guān)注的幾個(gè)問(wèn)題

了解了使用 MemoryHandler 實(shí)現的 Java  日志緩沖機制的內部細節和外部應用之后,來(lái)著(zhù)眼于兩處具體實(shí)現過(guò)程中遇到的問(wèn)題:Logger/Handler/LogRecord Level  的傳遞影響,以及如何在開(kāi)發(fā) MemoryHandler 過(guò)程中處理錯誤日志。

1. Level 的傳遞影響

Java.util.logging 中有三種類(lèi)型的 Level,分別是 Logger 的 Level,Handler 的 Level 和  LogRecord 的 Level. 前兩者可以通過(guò)配置文件設置。之后將日志的 Level 分別與 Logger 和 Handler 的  Level 進(jìn)行比較,過(guò)濾無(wú)須記錄的日志。在使用 Java Log 時(shí)需關(guān)注 Level 之間相互影響的問(wèn)題,尤其在遍歷 Logger  綁定了多個(gè) Handlers 時(shí)。如圖 3 所示:

圖 3. Java Log 中 Level 的傳遞影響

Java.util.logging.Logger 提供的 setUseParentHandlers  方法,也可能會(huì )影響到最終輸出終端的日志顯示。這個(gè)方法允許用戶(hù)將自身的日志條目打印一份到 Parent Logger 的輸出終端中。缺省會(huì )打印到  Parent Logger 終端。此時(shí),如果 Parent Logger Level 相關(guān)的設置與自身 Logger 不同,則打印到  Parent Logger 和自身中的日志條目也會(huì )有所不同。如圖 4 所示:

圖 4. 子類(lèi)日志需打印到父類(lèi)輸出終端

2. 開(kāi)發(fā) log 接口過(guò)程中處理錯誤日志

在開(kāi)發(fā) log 相關(guān)接口中調用自身接口打印 log,可能會(huì )陷入無(wú)限循環(huán)。Java.util.logging 中考慮到這類(lèi)問(wèn)題,提供了一個(gè)  ErrorManager 接口,供 Handler 在記錄日志期間報告任何錯誤,而非直接拋出異?;蛘{用自身的 log  相關(guān)接口記錄錯誤或異常。Handler 需實(shí)現 setErrorManager() 方法,該方法為此應用程序構造  java.util.logging.ErrorManager 對象,并在錯誤發(fā)生時(shí),通過(guò) reportError 方法調用  ErrorManager 的 error 方法,缺省將錯誤輸出到標準錯誤流,或依據 Handler 中自定義的實(shí)現處理錯誤流。關(guān)閉錯誤流時(shí),使用  Logger.removeHandler 移除此 Handler 實(shí)例。

兩種經(jīng)典使用場(chǎng)景,一種是自定義 MyErrorManager,實(shí)現父類(lèi)相關(guān)接口,在記錄日志的程序中調用  MyHandler.setErrorManager(new MyEroorManager()); 另一種是在 Handler 中自定義  ErrorManager 相關(guān)方法,示例如清單 7:

清單 7

public class MyHandler extends Handler{ // 在構造方法中實(shí)現 setErrorManager 方法 public MyHandler(){    ......     setErrorManager (new ErrorManager() {         public void  error (String msg, Exception ex, int code) {             System.err.println("Error reported by MyHandler "                              + msg + ex.getMessage());         }     }); } public void publish(LogRecord record){     if (!isLoggable(record)) return;     try {         // 一些可能會(huì )拋出異常的操作     } catch(Exception e) {         reportError ("Error occurs in publish ", e, ErrorManager.WRITE_FAILURE);     } } ...... }

logging.properties

logging.properties 文件是 Java 日志的配置文件,每一行以“key=value”的形式描述,可以配置日志的全局信息和特定日志配置信息,清單 8 是我們?yōu)闇y試代碼配置的 logging.properties。

清單 8. logging.properties 文件示例

#Level 等級 OFF > SEVERE > WARNING > INFO > CONFIG > FINE > FINER > FINEST > ALL # 為 FileHandler 指定日志級別 java.util.logging.FileHandler.level=WARNING # 為 FileHandler 指定 formatter java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter # 為自定義的 TestMemoryHandler 指定日志級別 com.ibm.test.MemoryHandler.level=INFO # 設置 TestMemoryHandler 最多記錄日志條數 com.ibm.test.TestMemoryHandler.size=1000 # 設置 TestMemoryHandler 的自定義域 useParentLevel com.ibm.test.TestMemoryHandler.useParentLevel=WARNING # 設置特定 log 的 handler 為 TestMemoryHandler com.ibm.test.handlers=com.ibm.test.TestMemoryHandler # 指定全局的 Handler 為 FileHandler handlers=java.util.logging.FileHandler

從 清單 8 中可以看出 logging.properties 文件主要是用來(lái)給 logger 指定等級(level),配置 handler 和 formatter 信息。

如何監聽(tīng) logging.properties

如果一個(gè)系統對安全要求比較高,例如系統需要對更改 logging.properties 文件進(jìn)行日志記錄,記錄何時(shí)何人更改了哪些記錄,那么應該怎么做呢?

這里可以利用 JDK 提供的 PropertyChangeListener 來(lái)監聽(tīng) logging.properties 文件屬性的改變。

例如創(chuàng )建一個(gè) LogPropertyListener 類(lèi),其實(shí)現了 java.benas.PropertyChangeListener  接口,PropertyChangeListener 接口中只包含一個(gè)  propertyChange(PropertyChangeEvent)方法,該方法的實(shí)現如清 9 所示。

清單 9. propertyChange 方法的實(shí)現

@Override public void propertyChange(PropertyChangeEvent event) {    if (event.getSource() instanceof LogManager){        LogManager manager=(LogManager)event.getSource();        update(manager);        execute();        reset();    } }

propertyChange(PropertyChangeEvent)方法中首先調用 update(LogManager)方法來(lái)找出  logging.properties 文件中更改的,增加的以及刪除的項,這部分代碼如清單 10 所示;然后調用 execute()  方法來(lái)執行具體邏輯,參見(jiàn) 清單 11;***調用 reset() 方法對相關(guān)屬性保存以及清空,如 清單 12 所示。

清單 10. 監聽(tīng)改變的條目

public void update(LogManager manager){  Properties logProps = null ;   // 使用 Java 反射機制獲取私有屬性    try {      Field f = manager.getClass().getDeclaredField("props");      f.setAccessible(true );      logProps=(Properties)f.get(manager);     }catch (Exception e){        logger.log(Level.SEVERE,"Get private field error.", e);         return ;    }    Set<String> logPropsName=logProps.stringPropertyNames();     for (String logPropName:logPropsName){         String newVal=logProps.getProperty(logPropName).trim();        // 記錄當前的屬性        newProps.put(logPropName, newVal);          // 如果給屬性上次已經(jīng)記錄過(guò)        if (oldProps.containsKey(logPropName)){             String oldVal = oldProps.get(logPropName);             if (newVal== null ?oldVal== null :newVal.equals(oldVal)){            // 屬性值沒(méi)有改變,不做任何操作         }else {             changedProps.put(logPropName, newVal);        }        oldProps.remove(logPropName);    }else {// 如果上次沒(méi)有記錄過(guò)該屬性,則其應為新加的屬性,記錄之         changedProps.put(logPropName, newVal);                      }     } }

代碼中 oldProps、newProps 以及 changedProps 都是 HashMap類(lèi)型,oldProps 存儲修改前  logging.properties 文件內容,newProps 存儲修改后 logging.properties  內容,changedProps 主要用來(lái)存儲增加的或者是修改的部分。

方法首先通過(guò) Java 的反射機制獲得 LogManager 中的私有屬性 props(存儲了 logging.properties  文件中的屬性信息),然后通過(guò)與 oldProps 比較可以得到增加的以及修改的屬性信息,*** oldProps 中剩下的就是刪除的信息了。

清單 11. 具體處理邏輯方法

private void execute(){  // 處理刪除的屬性  for (String prop:oldProps.keySet()){    // 這里可以加入其它處理步驟    logger.info("'"+prop+"="+oldProps.get(prop)+"'has been removed");            }  // 處理改變或者新加的屬性  for (String prop:changedProps.keySet()){      // 這里可以加入其它處理步驟      logger.info("'"+prop+"="+oldProps.get(prop)+"'has been changed or added");  } }

該方法是主要的處理邏輯,對修改或者刪除的屬性進(jìn)行相應的處理,比如記錄屬性更改日志等。這里也可以獲取當前系統的登錄者,和當前時(shí)間,這樣便可以詳細記錄何人何時(shí)更改過(guò)哪個(gè)日志條目。

清單 12. 重置所有數據結構

private void reset(){ oldProps = newProps; newProps= new HashMap< String,String>(); changedProps.clear(); }

eset() 方法主要是用來(lái)重置各個(gè)屬性,以便下一次使用。

當然如果只寫(xiě)一個(gè) PropertyChangeListener 還不能發(fā)揮應有的功能,還需要將這個(gè) PropertyChangeListener 實(shí)例注冊到 LogManager 中,可以通過(guò)清單 13 實(shí)現。

清單 13. 注冊 PropertyChangeListener

// 為'logging.properties'文件注冊監聽(tīng)器 LogPropertyListener listener= new LogPropertyListener(); LogManager.getLogManager().addPropertyChangeListener(listener);

如何實(shí)現自定義標簽

在 清單 8中有一些自定義的條目,比如 com.ibm.test.TestMemoryHandler。

useParentLever=WARNING”,表示如果日志等級超過(guò) useParentLever 所定義的等級 WARNING  時(shí),該條日志在 TestMemoryHandler 處理后需要傳遞到對應 Log 的父 Log 的 Handler 進(jìn)行處理(例如將發(fā)生了  WARNING 及以上等級的日志上下文緩存信息打印到文件中),否則不傳遞到父 Log 的 Handler  進(jìn)行處理,這種情況下如果不做任何處理,Java 原有的 Log 機制是不支持這種定義的。那么如何使得 Java Log  支持這種自定義標簽呢?這里可以使用 PropertyListener 對自定義標簽進(jìn)行處理來(lái)使得 Java Log  支持這種自定義標簽,例如對“useParentLever”進(jìn)行處理可以通過(guò)清單 14 實(shí)現。

清單 14

private void execute(){        // 處理刪除的屬性         for (String prop:oldProps.keySet()){             if (prop.endsWith(".useParentLevel")){                String logName=prop.substring(0, prop.lastIndexOf("."));                Logger log=Logger.getLogger(logName);                 for (Handler handler:log.getHandlers()){                     if (handler  instanceof TestMemoryHandler){                        ((TestMemoryHandler)handler)                            .setUseParentLevel(oldProps.get(prop));                         break ;                    }                }            }        }        // 處理改變或者新加的屬性         for (String prop:changedProps.keySet()){             if (prop.endsWith(".useParentLevel")){                // 在這里添加邏輯處理步驟            }        } }

在清單 14 處理之后,就可以在自定義的 TestMemoryHandler 中進(jìn)行判斷了,對 log 的等級與其域  useParentLevel 進(jìn)行比較,決定是否傳遞到父 Log 的 Handler 進(jìn)行處理。在自定義 TestMemoryHandler  中保存對應的 Log 信息可以很容易的實(shí)現將信息傳遞到父 Log 的 Handler,而保存對應 Log 信息又可以通過(guò)  PropertyListener 來(lái)實(shí)現,例如清單 15 更改了 清單 13中相應代碼實(shí)現這一功能。

清單 15

if (handler  instanceof TestMemoryHandler){     ((TestMemoryHandler)handler).setUseParentLevel(oldProps.get(prop));     ((TestMemoryHandler)handler).addLogger(log);       break ; }

具體如何處理自定義標簽的值那就看程序的需要了,通過(guò)這種方法就可以很容易在 logging.properties 添加自定義的標簽了。

自定義讀取配置文件

如果 logging.properties 文件更改了,需要通過(guò)調用  readConfiguration(InputStream)方法使更改生效,但是從 JDK 的源碼中可以看到  readConfiguration(InputStream)方法會(huì )重置整個(gè) Log 系統,也就是說(shuō)會(huì )把所有的 log 的等級恢復為默認值,將所有  log 的 handler 置為 null 等,這樣所有存儲的信息就會(huì )丟失。

比如,TestMemoryHandler 緩存了 1000 條 logRecord,現在用戶(hù)更改了 logging.properties  文件,并且調用了 readConfiguration(InputStream) 方法來(lái)使之生效,那么由于 JDK 本身的 Log  機制,更改后對應 log 的 TestMemoryHandler 就是新創(chuàng )建的,那么原來(lái)存儲的 1000 條 logRecord 的  TestMemoryHandler 實(shí)例就會(huì )丟失。

那么這個(gè)問(wèn)題應該如何解決呢?這里給出三種思路:

1). 由于每個(gè) Handler 都有一個(gè) close() 方法(任何繼承于 Handler 的類(lèi)都需要實(shí)現該方法),Java Log  機制在將 handler 置為 null 之前會(huì )調用對應 handler 的 close() 方法,那么就可以在 handler(例如  TestMemoryHandler)的 close() 方法中保存下相應的信息。

2). 研究 readConfiguration(InputStream)方法,寫(xiě)一個(gè)替代的方法,然后每次調用替代的方法。

3). 繼承 LogManager 類(lèi),覆蓋 readConfiguration(InputStream)方法。

這里***種方法是保存原有的信息,然后進(jìn)行恢復,但是這種方法不是很實(shí)用和高效;第二和第三種方法其實(shí)是一樣的,都是寫(xiě)一個(gè)替代的方法,例如可以在 替代的方法中對 Handler 為 TestMemoryHandler 的不置為 null,然后在讀取 logging.properties  文件時(shí)發(fā)現為 TestMemoryHandler 屬性時(shí),找到對應 TestMemoryHandler 的實(shí)例,并更改相應的屬性值(這個(gè)在清單  14 中有所體現),其他不屬于 TestMemoryHandler 屬性值的可以按照 JDK 原有的處理邏輯進(jìn)行處理,比如設置 log 的  level 等。

另一方面,由于 JDK1.6 及之前版本不支持文件修改監聽(tīng)功能,每次修改了 logging.properties 文件后需要顯式調用  readConfiguration(InputStream)才能使得修改生效,但是自 JDK1.7 開(kāi)始已經(jīng)支持對文件修改監聽(tīng)功能了,主要是在  java.nio.file.* 包中提供了相關(guān)的 API,這里不再詳述。

那么在 JDK1.7 之前,可以使用 apache 的 commons-io 庫中的 FileMonitor 類(lèi),在此也不再詳述。

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

色YEYE香蕉凹凸视频在线观看| 青青国产揄拍视频| 中文在线А√在线天堂中文| 最近免费中文字幕MV在线视频3| 亚洲女人自熨在线视频| 亚欧免费无码aⅴ在线观看|