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

封裝SLF4J/Log4j,不再處處定義logger變量

開發 后端
我們打印的日志通暢都帶有調用方的信息, 如類名、方法名、行數、時間等,其中類名、方法名、行數都是極其關鍵的信息,但是使用上述的方法來輸出日志的話,這三個信息都變成Logger這個類的信息,而不是調用方的信息, 這顯然是無法忍受的事。

自從開始使用日志組件后, 每個類都是這樣子的結構:

  1. public class A { 
  2.   public static final Logger logger = LoggerFactory.getLogger(A.class); 
  3.  
  4.  

這是一件相當煩人事,必須對他進行封裝,使得我們能夠通過這樣的方法來調用: 

  1. public class A { 
  2.     public void methodA() { 
  3.         Logger.debug("Nice!"); 
  4.     } 
  5.  

最簡單的版本

開始動手后,用最簡單的方法封裝出了***個版本:

  1. // cn.hjktech.slf4j.Logger 
  2. public class Logger { 
  3.     private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Logger.class);; 
  4.     ... 
  5.     public static void debug(...) { 
  6.         logger.debug(...); 
  7.         ... 
  8.     } 
  9.     ... 
  10.  

看起來很美好, 但測試后發現這種方法會有一個很嚴重的問題: 我們打印的日志通暢都帶有調用方的信息, 如類名、方法名、行數、時間等,其中類名、方法名、行數都是極其關鍵的信息,但是使用上述的方法來輸出日志的話,這三個信息都變成Logger這個類的信息,而不是調用方的信息, 這顯然是無法忍受的事。

當然不能就這樣了事,既然正常使用的方法能輸出正確的信息,那么肯定是有辦法可以實現的,我們希望最終的結果是調用Logger.debug(..)打印出來的信息都是完全正確的。

分析源碼

此時寫個demo來debug跟進一下:

  1. public class TestLog { 
  2.     @Test 
  3.     public void logTest() { 
  4.         // 在此處打斷點 
  5.         LoggerFactory.getLogger(TestLog.class).debug("看看執行流程"); 
  6.     } 
  7.  

發現最終輸出的日志字符串是在PatternLayout.format方法(Logback則是PatternLayoutBase.writeLoopOnConverters方法)中生成的,方法代碼如下:

  1. // Log4j 
  2. public String format(LoggingEvent event) { 
  3.     // Reset working stringbuffer 
  4.     if(sbuf.capacity() > MAX_CAPACITY) { 
  5.         sbuf = new StringBuffer(BUF_SIZE); 
  6.     } else { 
  7.         sbuf.setLength(0); 
  8.     } 
  9.  
  10.     PatternConverter c = head; 
  11.  
  12.     while(c != null) { 
  13.         c.format(sbuf, event); 
  14.         c = c.next
  15.     } 
  16.     return sbuf.toString(); 
  17.  

其中head指向一個類型為PatternConverter(Logback中是: Converter)的鏈表,這個鏈表的節點是在日志類初始化的時候,根據你日志配置文件里的ConversionPattern生成的,比如我的log4j.properties中是這樣配置的:

  1. log4j.appender.SOUT_LOGGER.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm,SSS} %p [%c] [%t] (%F:%L) %l - %m%n 

那么這個鏈表的結構就是(括號中代表存儲的信息):

  1. DatePatternConverter(時間點)           -> LiteralPatternConverter(" ")   ->  
  2. BasicPatternConverter(LEVEL)          -> LiteralPatternConverter("[")   ->  
  3. CategoryPatternConverter(LoggerName)  -> LiteralPatternConverter("] [") ->  
  4. BasicPatternConverter(線程名)          -> LiteralPatternConverter("] (") -> 
  5. LocationPatternConverter(所在類)       -> LiteralPatternConverter(":")   ->  
  6. LocationPatternConverter(所在行)       -> LiteralPatternConverter(") -") ->  
  7. BasicPatternConverter(日志串)          -> LiteralPatternConverter("\n")  ->  

根據這個鏈表生成日志字符串類似這樣:

  1. 2016-10-17-13-42,449 DEBUG [TestLog] [main] (TestLog.java:14) - Excuse me? 

那么現在目標很明確了,我們要使LocationPatternConverter的輸出為我們真正打印紙日的類的信息,繼續跟進到PatternConverter.format(LocationPatternConverter的父類)方法,其內部生成了一個LocationInfo對象,該類的構造方法中如下:

  1. for(int i = elements.length - 1; i >= 0; i--) { 
  2.     // 獲取第i幀的類名 
  3.     String thisClass = (String) getClassNameMethod.invoke(elements[i], noArgs); 
  4.     if(fqnOfCallingClass.equals(thisClass)) { 
  5.         // 如果類名和fqnOfCallingClass相等,則認為i + 1幀是代碼中實際調用方法的 
  6.         int caller = i + 1; 
  7.         if (caller < elements.length) { 
  8.             // 記錄實際調用類的類名 
  9.             className = prevClass; 
  10.             // 記錄實際調用的方法名 
  11.             methodName = (String) getMethodNameMethod.invoke(elements[caller], noArgs); 
  12.             // 記錄實際調用類所在的文件名 
  13.             fileName = (String) getFileNameMethod.invoke(elements[caller], noArgs); 
  14.             if (fileName == null) { 
  15.                 fileName = NA; 
  16.             } 
  17.             // 記錄調用日志方法的行數 
  18.             int line = ((Integer) getLineNumberMethod.invoke(elements[caller], noArgs)).intValue(); 
  19.             if (line < 0) { 
  20.                 lineNumber = NA; 
  21.             } else { 
  22.                 lineNumber = String.valueOf(line); 
  23.             } 
  24.             // 拼接成最終要輸出到日志的字符串, 如:TestLog.logTest(TestLog.java:14) 
  25.             StringBuffer buf = new StringBuffer(); 
  26.             buf.append(className); 
  27.             buf.append("."); 
  28.             buf.append(methodName); 
  29.             buf.append("("); 
  30.             buf.append(fileName); 
  31.             buf.append(":"); 
  32.             buf.append(lineNumber); 
  33.             buf.append(")"); 
  34.             this.fullInfo = buf.toString(); 
  35.         } 
  36.         return
  37.     } 
  38.     // 記錄上一幀的類名 
  39.     prevClass = thisClass; 
  40.  

其中elements是當前方法調用棧的堆棧軌跡,這段代碼通過遍歷堆棧軌跡每一幀的類名并和fqnOfCallingClass比較,如果相符的話,則認為它的上一幀是實際調用方法。

如下圖中,fqnOfCallingClass的值是org.slf4j.impl.Log4jLoggerAdapter,而在堆棧軌跡總可以發現類的上一個幀正好是我們的實際調用類TestLog.logTest:

因此,我們現在只需要讓fqnOfCallingClass的值變成我們封裝的日志類cn.hjktech.slf4j.Logger就大功告成了。fqnOfCallingClass是LoggingEvent.getLocationInformation創建LocationInfo時傳入的參數,而LoggingEvent又是在Category.forcedLog方法中創建的,并且繼續網上追蹤,會發現fqnOfCallingClass的值最終來源于org.slf4j.impl.Log4jLoggerAdapter這個類:

  1. public final class Log4jLoggerAdapter extends MarkerIgnoringBase implements LocationAwareLogger, Serializable { 
  2.     ... 
  3.     static final String FQCN = Log4jLoggerAdapter.class.getName(); 
  4.     ... 
  5.  

而如果沒有配合SLF4J使用時,fqnOfCallingClass的值則來源于org.apache.log4j.Logger類:

  1. public class Logger extends Category { 
  2.     ... 
  3.     private static final String FQCN = Logger.class.getName(); 
  4.     .... 
  5.  

代理Logger類來修改FQCN

好了,現在我們只需要修改這個值就行了。***反應是使用反射去掉final修飾符,然后修改它的值,這種方法雖然對我們自己的代碼可行,但是當引入其它框架,并且其它框架也使用的Log4j時,就會導致它們的日志信息出錯,因為它們并不是調用的我們封裝的Logger工具類,它們日志的堆棧軌跡中不會有我們工具類(如cn.hjktech.slf4j.Logger),因此我們需要另尋它法。

既然通過反射行不通, 那么我們可以通過動態代理的方式,在構造LoggingEvent對象之前將FQCN這個參數的值給替換掉,在跟蹤過程中發現Log4jLoggerAdapter最終都是調用的org.apache.log4j.Logger.log方法并將FQCN最為參數傳入,因此org.apache.log4j.Logger這個類就是我們要代理的類了。

了解JDK代理的人都知道,使用的條件是被代理類必須實現某一個接口,而org.apache.log4j.Logger.log這個方法并不是來自于某一個接口,所以我們選擇使用Cglib:

  1. // cn.hjktech.slf4j.Logger 
  2. public class Logger { 
  3.     private static org.slf4j.Logger logger; 
  4.     private static final String FQCN = Logger.class.getName(); 
  5.  
  6.     static { 
  7.         try { 
  8.             Enhancer eh = new Enhancer(); 
  9.             eh.setSuperclass(org.apache.log4j.Logger.class); 
  10.             eh.setCallbackType(LogInterceptor.class); 
  11.             Class c = eh.createClass(); 
  12.             Enhancer.registerCallbacks(c, new LogInterceptor[]{new LogInterceptor()}); 
  13.             Constructor<org.apache.log4j.Logger> constructor = c.getConstructor(String.class); 
  14.             org.apache.log4j.Logger loggerProxy= constructor.newInstance(Logger.class.getName()); 
  15.             ... 
  16.         } catch (...) { 
  17.             throw new RuntimeException("初始化Logger失敗", e); 
  18.         } 
  19.     } 
  20.  
  21.     private static class LogInterceptor implements MethodInterceptor { 
  22.         public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 
  23.             // 只攔截log方法。 
  24.             if (objects.length != 4 || !method.getName().equals("log")) 
  25.                 return methodProxy.invokeSuper(o, objects); 
  26.             // 替換傳給log方法的***個參數為我們自定義的FQCN 
  27.             objects[0] = FQCN; 
  28.             return methodProxy.invokeSuper(o, objects); 
  29.         } 
  30.     } 
  31.  

代理defaultFactory

現在我們已經有了被代理的loggerProxy對象了,我們還需要將這個對象賦值給Log4jLoggerAdapter的logger成員變量,

logger成員變量是在Log4jLoggerAdapter的構造方法中被作為參數傳入的,它的來源如下圖:

從上圖中可以看到,LogManager.getLoggerRepository方法返回的對象中持有defaultFactory對象,因此我還需要代理這個對象,將它產生的'logger'對象替換成我們的'logger'就大功告成了,并且makeNewLoggerInstance方法是在LoggerFactory接口中定義的,所以我們只需要使用JDK的動態代理就可以完成了。實現代碼如下:

  1. static { 
  2.     try { 
  3.         ... 
  4.         LoggerRepository loggerRepository = LogManager.getLoggerRepository(); 
  5.         org.apache.log4j.spi.LoggerFactory lf = ReflectionUtil.getFieldValue(loggerRepository, "defaultFactory"); 
  6.         Object loggerFactoryProxy = Proxy.newProxyInstance( 
  7.             LoggerFactory.class.getClassLoader(), 
  8.             new Class[]{LoggerFactory.class}, 
  9.             new NewLoggerHandler(loggerProxy) 
  10.         ); 
  11.  
  12.         ReflectionUtil.setFieldValue(loggerRepository, "defaultFactory", loggerFactoryProxy); 
  13.             logger = org.slf4j.LoggerFactory.getLogger(Logger.class.getName()); 
  14.         ReflectionUtil.setFieldValue(loggerRepository, "defaultFactory", lf); 
  15.     } catch (...) { 
  16.         throw new RuntimeException("初始化Logger失敗", e); 
  17.     } 
  18.  
  19. private static class NewLoggerHandler implements InvocationHandler { 
  20.     private final org.apache.log4j.Logger proxyLogger; 
  21.  
  22.     public NewLoggerHandler(org.apache.log4j.Logger proxyLogger) { 
  23.         this.proxyLogger = proxyLogger; 
  24.     } 
  25.  
  26.     @Override 
  27.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  28.         return proxyLogger; 
  29.     } 
  30.  

實現流程和最終代碼

我們最終實現方案如下:

Logger的代碼如下:

  1. public class Logger { 
  2.     private static org.slf4j.Logger logger; 
  3.     private static final String FQCN = Logger.class.getName(); 
  4.      
  5.     static { 
  6.         try { 
  7.             Enhancer eh = new Enhancer(); 
  8.             eh.setSuperclass(org.apache.log4j.Logger.class); 
  9.             eh.setCallbackType(LogInterceptor.class); 
  10.             Class c = eh.createClass(); 
  11.             Enhancer.registerCallbacks(c, new LogInterceptor[]{new LogInterceptor()}); 
  12.  
  13.             Constructor<org.apache.log4j.Logger> constructor = c.getConstructor(String.class); 
  14.             org.apache.log4j.Logger loggerProxy = constructor.newInstance(Logger.class.getName()); 
  15.  
  16.             LoggerRepository loggerRepository = LogManager.getLoggerRepository(); 
  17.             org.apache.log4j.spi.LoggerFactory lf = ReflectionUtil.getFieldValue(loggerRepository, "defaultFactory"); 
  18.             Object loggerFactoryProxy = Proxy.newProxyInstance( 
  19.                 LoggerFactory.class.getClassLoader(), 
  20.                 new Class[]{LoggerFactory.class}, 
  21.                 new NewLoggerHandler(loggerProxy) 
  22.             ); 
  23.  
  24.             ReflectionUtil.setFieldValue(loggerRepository, "defaultFactory", loggerFactoryProxy); 
  25.             logger = org.slf4j.LoggerFactory.getLogger(Logger.class.getName()); 
  26.             ReflectionUtil.setFieldValue(loggerRepository, "defaultFactory", lf); 
  27.         } catch ( 
  28.             IllegalAccessException | 
  29.                 NoSuchMethodException | 
  30.                 InvocationTargetException | 
  31.                 InstantiationException e) { 
  32.             throw new RuntimeException("初始化Logger失敗", e); 
  33.         } 
  34.     } 
  35.  
  36.     private static class LogInterceptor implements MethodInterceptor { 
  37.         public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 
  38.             // 只攔截log方法。 
  39.             if (objects.length != 4 || !method.getName().equals("log")) 
  40.                 return methodProxy.invokeSuper(o, objects); 
  41.             objects[0] = FQCN; 
  42.             return methodProxy.invokeSuper(o, objects); 
  43.         } 
  44.     } 
  45.  
  46.     private static class NewLoggerHandler implements InvocationHandler { 
  47.         private final org.apache.log4j.Logger proxyLogger; 
  48.  
  49.         public NewLoggerHandler(org.apache.log4j.Logger proxyLogger) { 
  50.             this.proxyLogger = proxyLogger; 
  51.         } 
  52.  
  53.         @Override 
  54.         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  55.             return proxyLogger; 
  56.         } 
  57.     } 
  58.  
  59.     // 剩下的Logger需要封裝的方法可以根據自己的需要來實現 
  60.     // 我個人認為slf4j的api足夠好用了,所以大部分只是寫了一些類似下面的代碼 
  61.     public static void debug(String msg) { 
  62.         logger.debug(msg); 
  63.     } 
  64.  

ReflectionUtil的代碼如下:

  1. public class ReflectionUtil { 
  2.     public static <T> T getFieldValue(@NotNull Object object, 
  3.                                       @NotNull String fullName) throws IllegalAccessException { 
  4.         return getFieldValue(object, fullName, false); 
  5.     } 
  6.  
  7.     public static <T> T getFieldValue(@NotNull Object object, 
  8.                                       @NotNull String fieldName, 
  9.                                       boolean traceable) throws IllegalAccessException { 
  10.         Field field; 
  11.         String[] fieldNames = fieldName.split("\\."); 
  12.         for (String targetField : fieldNames) { 
  13.             field = searchField(object.getClass(), targetField, traceable); 
  14.             if (field == null
  15.                 return null
  16.  
  17.             object = getValue(object, field); 
  18.         } 
  19.  
  20.         return (T) object; 
  21.     } 
  22.  
  23.     private static Field searchField(Class c, String targetField, boolean traceable) { 
  24.         do { 
  25.             Field[] fields = c.getDeclaredFields(); 
  26.             for (Field f : fields) { 
  27.                 if (f.getName().equals(targetField)) { 
  28.                     return f; 
  29.                 } 
  30.             } 
  31.             c = c.getSuperclass(); 
  32.             traceable = traceable && c != Object.class; 
  33.         } while (traceable); 
  34.  
  35.         return null
  36.     } 
  37.  
  38.     private static <T> T getValue(Object target, Field field) throws IllegalAccessException { 
  39.         if (!field.isAccessible()) 
  40.             field.setAccessible(true); 
  41.         return (T) field.get(target); 
  42.     } 
  43.  
  44.     public static boolean setFieldValue(@NotNull Object target, 
  45.                                         @NotNull String fieldName, 
  46.                                         @NotNull Object value) throws IllegalAccessException { 
  47.         return setFieldValue(target, fieldName, value, false); 
  48.     } 
  49.  
  50.     public static boolean setFieldValue(@NotNull Object target, 
  51.                                         @NotNull String fieldName, 
  52.                                         @NotNull Object value, 
  53.                                         boolean traceable) throws IllegalAccessException { 
  54.         Field field = searchField(target.getClass(), fieldName, traceable); 
  55.         if (field != null
  56.             return setValue(field, target, value); 
  57.         return false
  58.     } 
  59.  
  60.     private static boolean setValue(Field field, Object target, Object value) throws IllegalAccessException { 
  61.         if (!field.isAccessible()) 
  62.             field.setAccessible(true); 
  63.         field.set(target, value); 
  64.         return true
  65.     } 
  66.  

測試 

  1. public class TestLog { 
  2.  
  3.     @Test 
  4.     public void logTest() { 
  5.         Logger.debug((Marker)null"這是調用封裝的Logger輸出日志"); 
  6.         LoggerFactory.getLogger(TestLog.class).info("常規方法輸出日志"); 
  7.     } 
  8.  

輸出結果:

  1. 2016-10-19-15-00,308 DEBUG [cn.hjktech.slf4j.Logger] [main] (TestLog.java:13) TestLog.logTest(TestLog.java:13) - 這是調用封裝的Logger輸出日志  
  2. 2016-10-19-15-00,311 INFO [TestLog] [main] (TestLog.java:14) TestLog.logTest(TestLog.java:14) - 常規方法輸出日志  
責任編輯:龐桂玉 來源: segmentfault
相關推薦

2020-01-07 10:06:26

Slf4jLog4JLogback

2023-01-11 21:22:32

Java服務器

2024-03-01 16:52:02

SLF4J日志框架

2023-10-28 16:19:18

Android日志

2013-02-20 09:42:34

JavaLogbackSLF4J

2022-02-15 17:51:38

Log4j漏洞網絡安全

2022-02-13 16:18:57

JetBrainsIntelliJLog4j

2022-03-25 13:42:15

Log4j漏洞網絡安全

2023-10-07 10:08:54

2021-12-14 23:44:26

漏洞Log4j項目

2022-03-30 11:29:53

漏洞補丁Spring

2009-06-12 17:03:51

JBoss和log4j

2020-11-04 12:33:08

Log4j 2日志Logback

2025-05-26 08:50:00

SLF4JMDC全鏈路追蹤

2021-03-15 18:47:25

日志開發源碼

2025-01-20 08:10:00

微服務架構SLF4J

2022-12-30 08:31:27

MDC查詢日志

2021-12-24 09:52:31

Traefik Log4J 漏洞

2022-01-24 10:02:53

漏洞微軟網絡攻擊

2021-12-13 01:49:34

漏洞Log4j代碼
點贊
收藏

51CTO技術棧公眾號

日韩av一区二区在线观看| 国产精品国产精品国产专区不片 | 在线激情小视频| 久久99久久久久久久久久久| 美女精品视频一区| 国产中文字幕一区二区| 国产一区高清| 亚洲一二三四久久| 欧美日韩亚洲一区二区三区在线观看| 伊人网av在线| 亚洲精选成人| 日韩一区二区av| 亚洲av成人片色在线观看高潮| 天堂久久午夜av| 亚洲一区二区高清| 日韩中文字幕一区| 亚洲第一精品网站| 日av在线不卡| 97免费在线视频| 99精品中文字幕| 欧美绝顶高潮抽搐喷水合集| 欧美人动与zoxxxx乱| 欧美 日韩 国产 高清| 乱人伦中文视频在线| 99re这里只有精品首页| 91中文字幕在线| 波多野结衣视频在线看| 亚洲高清久久| 久久亚洲国产成人| 黄色av免费播放| 神马午夜久久| 精品国产乱码久久久久久浪潮| 天天爽天天爽夜夜爽| av伦理在线| 亚洲黄色免费网站| 伊人久久大香线蕉成人综合网 | 欧美性www| 婷婷六月综合亚洲| 欧美图片激情小说| 91精选在线| 亚洲视频网在线直播| 神马影院我不卡午夜| 亚洲欧美色视频| 成人午夜激情影院| 成人福利免费观看| 最近中文字幕在线观看视频| 国产一区二区高清| 97国产精品久久| 精品少妇theporn| 欧美日韩三级电影在线| 久久艳片www.17c.com| 精品女人久久久| 日韩理论电影院| 国产一区二区三区在线视频| 中日韩精品一区二区三区| 西野翔中文久久精品国产| 亚洲国产91精品在线观看| 娇妻高潮浓精白浆xxⅹ| 国产精品一区二区中文字幕| 精品久久一区二区三区| 图片区偷拍区小说区| 91蜜桃臀久久一区二区| 亚洲国产精品福利| 99久久久久久久久久| 妖精视频一区二区三区免费观看| 亚洲精品资源美女情侣酒店| 免费污网站在线观看| 国产成人一区| 少妇av一区二区三区| 一区二区三区四区五区| 欧美成人首页| 国内精品久久久久影院 日本资源| 免费毛片在线播放免费| 亚洲区一区二| 日韩暖暖在线视频| 亚洲一卡二卡在线观看| 国产一区二区h| 成人在线免费网站| 婷婷在线免费视频| 久久伊99综合婷婷久久伊| 日韩成人在线资源| 日本免费中文字幕在线| 洋洋av久久久久久久一区| 男人日女人视频网站| 中文字幕乱码在线播放| 在线精品视频一区二区三四| 日韩av片免费观看| 中文在线综合| 亚洲摸下面视频| www.日本高清视频| 国产精品av久久久久久麻豆网| 久久久久久久久久久人体| 一级黄色av片| 国产乱淫av一区二区三区| 精品久久久久久综合日本| 高h视频在线| 亚洲高清在线视频| 无限资源日本好片| 国产丝袜一区| 色妞欧美日韩在线| 日本学生初尝黑人巨免费视频| 久久九九精品| 91久久极品少妇xxxxⅹ软件| 青青草手机在线| 亚洲欧美日韩国产另类专区| 精品一区二区中文字幕| 成人97精品毛片免费看| 亚洲男人第一av网站| www欧美com| 丝袜美腿亚洲一区二区图片| 99国产超薄肉色丝袜交足的后果 | 91麻豆精品视频| 中文字幕一区二区三区精彩视频| a√中文在线观看| 欧美日韩国产美女| www.自拍偷拍| 欧美三级特黄| 国产欧美日韩亚洲精品| 性感美女福利视频| 亚洲午夜在线电影| 爱豆国产剧免费观看大全剧苏畅| 午夜精品福利影院| 久久免费视频在线观看| 国产精品久久久久久免费| 91视频.com| 嫩草影院中文字幕| 2020国产精品小视频| 亚洲欧美国产高清va在线播| 国产亚洲精品码| 国产在线不卡视频| 亚洲一区二区高清视频| 丝袜美腿诱惑一区二区三区| 亚洲福利在线观看| 久久久久久天堂| 精品一区二区在线看| 日韩亚洲欧美精品| 欧美精品高清| 亚洲女人初尝黑人巨大| 国产精品老女人| 国产999精品久久久久久绿帽| 亚洲免费av网| 日本电影久久久| 色吧影院999| 中文字幕在线观看精品| 国产精品麻豆网站| 污视频免费在线观看网站| 国产精品一在线观看| 日本中文字幕成人| 精品成人一区二区三区免费视频| 精品久久久久久亚洲国产300| www.啪啪.com| 一本不卡影院| 欧美人与性禽动交精品| 不卡一二三区| 亚洲网址你懂得| 在线观看免费中文字幕| 欧美激情一区二区| 中文字幕在线综合| 99精品视频在线观看免费播放| 国产一区视频在线| 天堂8中文在线| 精品国产一区二区在线观看| 精品视频在线观看免费| 99re热视频这里只精品| 国产精品69页| 日产精品一区二区| 亚洲一区二区三区视频| 日本孕妇大胆孕交无码| 亚洲福利视频久久| 免费视频网站在线观看入口| 国产精品免费网站在线观看| 久久久九九九热| 亚洲国产mv| 欧美日韩亚洲在线| 91精品一区| 久久久免费电影| 邻居大乳一区二区三区| 欧美日韩一级片在线观看| 日本中文在线视频| a美女胸又www黄视频久久| 国产日韩一区二区在线观看| 日韩欧美中文| 国产不卡一区二区三区在线观看 | 国产精品亚洲综合天堂夜夜| 亚洲性图自拍| 亚洲美女www午夜| 97国产精品久久久| 亚洲va中文字幕| 免费一级特黄3大片视频| 国产乱码精品一区二区三| 欧美综合在线播放| 色999日韩| 国产精品一级久久久| 欧美日韩免费观看视频| 麻豆成人在线看| 男人久久精品| 日韩一区二区三区精品视频| 亚洲天堂一区在线| ㊣最新国产の精品bt伙计久久| 亚洲色偷偷色噜噜狠狠99网 | 亚洲国产欧美日韩另类综合| 中国女人特级毛片| 懂色av中文一区二区三区 | 欧美网站免费| 2024亚洲男人天堂| 麻豆免费在线观看| 亚洲深夜福利在线| 熟妇高潮一区二区三区| 欧美精品在线一区二区| 国产又粗又猛又黄视频| 一二三区精品视频| 国产亚洲精品久久久久久豆腐| 97se狠狠狠综合亚洲狠狠| 国产大片一区二区三区| 久久在线精品| 天堂8在线天堂资源bt| 久久视频精品| 欧美不卡1区2区3区| 51精品国产| 91久久精品国产91久久| 成人精品电影在线| 97超碰国产精品女人人人爽| 在线看福利影| 久久精品99国产精品酒店日本| 青青久在线视频| 亚洲国产精品成人av| а√中文在线资源库| 欧美群妇大交群的观看方式| 日本一本在线观看| 日本精品视频一区二区| 中文字幕亚洲精品在线| 亚洲va欧美va天堂v国产综合| 日韩视频中文字幕在线观看| 国产精品狼人久久影院观看方式| 91网站免费视频| 91免费国产在线| 国产精品第七页| 99re热这里只有精品视频| 五十路六十路七十路熟婆 | 91麻豆精品国产91久久久| 中文 欧美 日韩| 日本高清视频一区二区| caoporn国产| 色综合网色综合| 精品人妻无码一区二区性色| 欧美日韩亚洲一区二| 97久久久久久久| 色哟哟在线观看一区二区三区| 欧美日韩综合在线观看| 欧美性精品220| 4438国产精品一区二区| 91久久线看在观草草青青| 无码一区二区三区在线观看| 色综合久久中文字幕综合网| 六月丁香婷婷综合| 色婷婷av一区二区三区大白胸| 久久久成人免费视频| 在线观看精品一区| 一区两区小视频| 日韩欧美在线网站| 亚洲精品久久久蜜桃动漫 | 色哟哟国产精品| 亚洲欧美日韩一区二区三区四区| 在线看日本不卡| 国产精品丝袜黑色高跟鞋| 欧美一级久久久| 欧美一级一区二区三区| 亚洲美女av电影| 午夜视频成人| 欧美国产高跟鞋裸体秀xxxhd| 国产精品一品| 欧洲亚洲免费视频| 久久er热在这里只有精品66| 亚洲tv在线观看| 你懂的在线观看一区二区| 欧美日韩在线不卡一区| 久久理论电影| www.av91| 天堂一区二区在线| 91蝌蚪视频在线| www.成人网.com| 女人黄色一级片| 一区二区三区四区av| 久久久久久久久久免费视频| 在线观看日韩毛片| av综合在线观看| 日韩电影中文 亚洲精品乱码| 3p在线观看| 久久久久久久爱| 国产原创一区| 精品国产一区二区三| 日本一区二区高清不卡| 精品无码国产一区二区三区av| 久久蜜桃精品| xxxx视频在线观看| 中国色在线观看另类| 国产精品a成v人在线播放| 欧美日韩亚洲另类| 免费看黄网站在线观看| 日韩中文字幕免费视频| 阿v视频在线| 91精品久久久久久久久中文字幕 | 国产丝袜一区二区三区| 99久久精品免费观看国产| 国产97在线亚洲| 成人h动漫免费观看网站| 亚洲午夜精品一区二区三区| 一区二区高清| 1314成人网| 中文字幕一区二区在线播放| 国产精品黄色大片| 日韩一区二区中文字幕| 成在在线免费视频| 91国偷自产一区二区三区的观看方式| 超碰国产精品一区二页| 日本精品免费| 一本不卡影院| 白嫩情侣偷拍呻吟刺激| 亚洲欧洲无码一区二区三区| 日本高清不卡码| 亚洲精品美女在线| 欧美黑人猛交的在线视频| 91精品久久久久久久久久久久久| 蜜臀av免费一区二区三区| 日本精品福利视频| 极品少妇xxxx偷拍精品少妇| 国产欧美一区二区三区在线观看视频 | 欧美第一黄网| 亚洲精品激情| 在线观看亚洲免费视频| 亚洲综合久久久| 99产精品成人啪免费网站| 日韩中文娱乐网| 精品三区视频| 日韩免费三级| 日韩电影免费一区| 精品日韩在线视频| 在线亚洲免费视频| 免费在线黄色网址| 国产不卡av在线| 国内成人精品| 五月天婷婷激情视频| 国产日本欧美一区二区| 一级黄色av片| 正在播放欧美一区| 久久免费资源| 日本特级黄色大片| 国产乱人伦精品一区二区在线观看| 成人免费毛片xxx| 日韩三级免费观看| 欧洲中文在线| 国产乱码一区| 亚洲专区免费| 中文字幕有码在线播放| 欧美性感一区二区三区| 日韩大片在线永久免费观看网站| 成人黄色在线播放| 欧美91视频| 中文字幕精品视频在线| 狠狠色狠狠色综合日日小说| 久久久久久久影视| 国产剧情日韩欧美| 一精品久久久| 国产视频精品视频| 日韩欧美aaa| 成年午夜在线| 91亚洲精品一区| 黑人一区二区| 亚洲国产欧美视频| 欧美日韩在线直播| a黄色片在线观看| 国产伦精品一区二区三区高清| 男人天堂欧美日韩| 三级影片在线观看| 欧美精品一区在线观看| 日韩成人动漫| 五月天av影院| www.性欧美| 亚洲一区中文字幕永久在线| 欧美日韩aaaa| 一区二区三区韩国免费中文网站| 黄色小视频免费网站| 亚洲国产欧美一区二区三区丁香婷 | 久久99精品一区二区三区三区| 欧美三根一起进三p| 日韩精品在线播放| 成人免费观看49www在线观看| 青青草国产免费| 国产精品系列在线| 天堂在线资源8| 国产精品自产拍在线观看中文| 欧美涩涩网站| 黄免费在线观看| 337p日本欧洲亚洲大胆色噜噜| 偷拍视频一区二区三区| 日本一道在线观看| 久久久www免费人成精品| 亚洲AV无码一区二区三区少妇| 国产精品av网站| 在线观看不卡|