日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如果你只写CRUD,那这种技术栈你永远碰不到

發布時間:2025/3/21 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如果你只写CRUD,那这种技术栈你永远碰不到 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

寫這篇文章的時候我在想可能大部分程序員包括你我,常常都在忙于業務開發或奔波在日常維護與修復BUG的路上,當不能從中吸取技術營養與改變現狀后,就像一臺恒定運行的機器,逃不出限定宇宙速度的一個圈里。可能你也會有自己的難處,平時加班太晚沒有時間學習、周末家里瑣事太多沒有精力投入,放假計劃太滿沒有空閑安排??傊?#xff0c;學習就會被擱置。而當一年年的過去后,當自己的年齡與能力不成匹配后又會后悔沒有給多投入一些時間學習成長。

尤其是一線編碼的技術人,除了我們所能看到的在技術框架里(SSM)開發的業務代碼,你是否有遇到過學習瓶頸,而這種瓶頸又是你自己不知道自己不會什么,就像下面這些技術列表里,你有了解多少;

1. javaagent
2. asm
3. jvmti
4. javaassit
5. netty
6. 算法,搜索引擎
7. cglib
8. 混沌工程
9. 中間件開發
10. 高級測試;壓力測試、鏈路測試、流量回放、流量染色
11. 故障系列;突襲、重現、演練
12. 分布式的數據一致性
13. 文件操作;es、hive
14. 注冊中心;zookeeper、Eureka
15. 互聯網工程開發技術棧;spring、mybaits、網關、rpc(thrift, grpc, dubbo)、mq、緩存redis、分庫分表、定時任務、分布式事物、限流、熔斷、降級
16. 數據庫binlog解析?
17. 架構設計;DDD領域驅動設計、微服務、服務治理
18. 容器;k8s, docker
19. 分布式存儲;ceph
20. 服務istio
21. 壓測 jmter
22. Jenkins-部署java代碼項目 + ansible
23. 全鏈路監控,分布式追蹤
24. 語音識別、語音合成
26. lvs nginx haproxy iptables
27. hadoop mapreduce hive sqoop hbase flink kylin druid

  • 類的代理,如cglib
  • 混沌工程
  • 反向工程
  • 結合 javaagent 做到非入侵式監控,方法耗時、日志、機器性能等等
  • 破解
  • ASM 是一個 Java 字節碼操控框架。它能被用來動態生成類或者增強既有類的功能。ASM 可以直接產生二進制 class 文件,也可以在類被加載入 Java 虛擬機之前動態改變類行為。Java class 被存儲在嚴格格式定義的 .class 文件里,這些類文件擁有足夠的元數據來解析類中的所有元素:類名稱、方法、屬性以及 Java 字節碼(指令)。ASM 從類文件中讀入信息后,能夠改變類行為,分析類信息,甚至能夠根據用戶要求生成新類。

    為了更方便的學習ASM,我將《ASM4使用手冊》以及一些技術點整理成在線文檔,可以隨時方便查閱(http://asm.itstack.org);

    另外關于本文中出現的代碼例子,可以通過在公眾號(bugstack蟲洞棧)內回復,源碼下載獲取。

    二、環境配置

  • jdk 1.8
  • idea 2019.3.1
  • asm-commons 6.2.1
  • 三、工程信息

    • itstack-demo-asm-01:字節碼編程,HelloWorld
    • itstack-demo-asm-02:字節碼編程,兩數之和
    • itstack-demo-asm-03:字節碼增強,輸出入參
    • itstack-demo-asm-04:字節碼增強,調用外部方法

    四、HelloWorld還可以這樣寫

    你所熟悉的HelloWorld是不這樣;

    public class HelloWorld {public static void main(String[] var0) {System.out.println("Hello World");} }

    那你有嘗試反解析下他的類查看下匯編指令嗎,javap -c HelloWorld

    public class org.itstack.demo.test.HelloWorld {public org.itstack.demo.test.HelloWorld();Code:0: aload_01: invokespecial #1 ? ? ? ? ? ? ? ? ?// Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: getstatic ? ? #2 ? ? ? ? ? ? ? ? ?// Field java/lang/System.out:Ljava/io/PrintStream;3: ldc ? ? ? ? ? #3 ? ? ? ? ? ? ? ? ?// String Hello World5: invokevirtual #4 ? ? ? ? ? ? ? ? ?// Method java/io/PrintStream.println:(Ljava/lang/String;)V8: return }
    指令描述
    getstatic獲取靜態字段的值
    ldc常量池中的常量值入棧
    invokevirtual運行時方法綁定調用方法
    return?? ?void函數返回

    如果你還感興趣其他指令,可以參考這個字節碼指令表:Go!

    好! 以上呢,是我很熟悉的一段代碼了,那么現在我們把這段代碼用ASM方式寫出來;

    import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes;private static byte[] generate() {ClassWriter classWriter = new ClassWriter(0);// 定義對象頭;版本號、修飾符、全類名、簽名、父類、實現的接口classWriter.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, "org/itstack/demo/asm/AsmHelloWorld", null, "java/lang/Object", null);// 添加方法;修飾符、方法名、描述符、簽名、異常MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);// 執行指令;獲取靜態屬性methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");// 加載常量 load constantmethodVisitor.visitLdcInsn("Hello World");// 調用方法methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);// 返回methodVisitor.visitInsn(Opcodes.RETURN);// 設置操作數棧的深度和局部變量的大小methodVisitor.visitMaxs(2, 1);// 方法結束methodVisitor.visitEnd();// 類完成classWriter.visitEnd();// 生成字節數組return classWriter.toByteArray(); }

    以上的代碼,“小朋友,你是否有很多問好???^1024”,其實以上的代碼都是來自于 ASM 框架的代碼,這里面所有的操作與我們使用使用 javap -c XXX 所反解析出的字節碼是一樣的,只不過是反過來使用指令來編寫代碼。

  • 定義一個類的生成 ClassWriter
  • 設定版本、修飾符、全類名、簽名、父類、實現的接口,其實也就是那句;public class HelloWorld
  • 接下來開始創建方法,方法同樣需要設定;修飾符、方法名、描述符等。這里面有幾個固定標識;
  • 類型描述符

    | Java 類型 | 類型描述符 |
    |:—|:—|
    | boolean | Z |
    | char | C |
    | byte | B |
    | short | S |
    | int | I |
    | float | F |
    | long | J |
    | double | D |
    | Object | Ljava/lang/Object; |
    | int[] | [I |
    | Object[][] | [[Ljava/lang/Object; |

    方法描述符

    | 源文件中的方法聲明 | 方法描述符 |
    |:—|:—|
    | void m(int i, float f) | (IF)V |
    | int m(Object o) | (Ljava/lang/Object;)I |
    | int[] m(int i, String s) | (ILjava/lang/String;)[I |
    | Object m(int[] i) | ([I)Ljava/lang/Object; |

    ([Ljava/lang/String;)V== void main(String[] args)

  • 執行指令;獲取靜態屬性。主要是獲得 System.out
  • 加載常量 load constant,輸出我們的HelloWorld methodVisitor.visitLdcInsn("Hello World");
  • 最后是調用輸出方法并設置空返回,同時在結尾要設置操作數棧的深度和局部變量的大小
  • 這樣輸出一個 HelloWorld 是不還是蠻有意思的,雖然你可能覺得這編碼起來實在太難了吧,也非常難理解。首先如果你看過我的專欄,用《Java寫一個Jvm虛擬機》,那么你可能會感受到這里面的知識點還是不那么陌生的。另外這里的編寫,ASM還提供了插件,可以方便的讓你開發字節碼。接下來就介紹一下使用方式。

    五、有插件的幫助字節碼開發也不是很難

    對于新人來說如果用字節碼增強開發一些東西確實挺難,尤其是一些復雜的代碼塊使用字節碼指令操作還是很有難度的。那么,其實也是有簡單辦法就是使用 ASM 插件。這個插件可以很輕松的讓你看到一段代碼的指令碼以及如何用ASM去開發。

    安裝插件(ASM Bytecode Outline)

    測試使用

    是不是看到有插件的幫助下,心里有所激動了,至少寫這樣的東西有了抓手。這樣你就可以很方便的去操作一些增強字節碼的功能了。

    六、用字節碼寫出一個兩數之和計算

    好!有了上面的插件,也有了一些基礎知識的了解。那么我們開發一個計算兩數之和的方法,之后運行計算結果。

    這是我們的目標

    public class SumOfTwoNumbers {public int sum(int i, int m) {return i + m;}}

    使用字節碼編程方式實現

    import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes;private static byte[] generate() {ClassWriter classWriter = new ClassWriter(0);{MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);methodVisitor.visitInsn(Opcodes.RETURN);methodVisitor.visitMaxs(1, 1);methodVisitor.visitEnd();}{// 定義對象頭;版本號、修飾符、全類名、簽名、父類、實現的接口classWriter.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, "org/itstack/demo/asm/AsmSumOfTwoNumbers", null, "java/lang/Object", null);// 添加方法;修飾符、方法名、描述符、簽名、異常MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "sum", "(II)I", null, null);methodVisitor.visitVarInsn(Opcodes.ILOAD, 1);methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);methodVisitor.visitInsn(Opcodes.IADD);// 返回methodVisitor.visitInsn(Opcodes.IRETURN);// 設置操作數棧的深度和局部變量的大小methodVisitor.visitMaxs(2, 3);methodVisitor.visitEnd();}// 類完成classWriter.visitEnd();// 生成字節數組return classWriter.toByteArray(); }

    上面有兩個括號 {},第一個是用于生成一個空的構造函數

    public AsmSumOfTwoNumbers() { }

    接下來的指令就比較簡單了,首先使用 ILOAD進行數值的兩次壓棧也就是弄到操作數棧里去操作,接下來開始執行 IADD,將兩數相加。

    最后返回結果 IRETURN,注意是返回的 I 類型。到此這段方法快就實現完成了。反編譯后如下;

    // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) //package org.itstack.demo.asm;public class AsmSumOfTwoNumbers {public AsmSumOfTwoNumbers() {}public int doSum(int var1, int var2) {return var1 + var2;} }

    執行代碼塊

    public static void main(String[] args) throws Exception {// 生成二進制字節碼byte[] bytes = generate();// 輸出字節碼outputClazz(bytes);// 加載AsmSumOfTwoNumbersGenerateSumOfTwoNumbers generateSumOfTwoNumbers = new GenerateSumOfTwoNumbers();Class<?> clazz = generateSumOfTwoNumbers.defineClass("org.itstack.demo.asm.AsmSumOfTwoNumbers", bytes, 0, bytes.length);// 反射獲取 main 方法Method method = clazz.getMethod("sum", int.class, int.class);Object obj = method.invoke(clazz.newInstance(), 6, 2);System.out.println(obj); }

    這段執行操作和我們在使用 java 的反射操作一樣,也是比較容易的。此時我們是調用了新的字節碼類,同時還將字節碼輸出方便我們查看生成的 class類。

    七、在原有方法上字節碼增強監控耗時

    到這我們基本了解到通過字節碼編程,可以動態的生成一個類。但是在實際使用的過程中,我們可能有的時候是需要修改一個原有的方法,在開始和結尾添加一些代碼,來監控這個方法的耗時。這也是非侵入式監控的最基本模型。

    定義一個方法

    public class MyMethod {public String queryUserInfo(String uid) {System.out.println("xxxx");System.out.println("xxxx");System.out.println("xxxx");System.out.println("xxxx");return uid;}}

    像這個方法插入監控

    public class TestMonitor extends ClassLoader {public static void main(String[] args) throws IOException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {ClassReader cr = new ClassReader(MyMethod.class.getName());ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);{MethodVisitor methodVisitor = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);methodVisitor.visitInsn(Opcodes.RETURN);methodVisitor.visitMaxs(1, 1);methodVisitor.visitEnd();}ClassVisitor cv = new ProfilingClassAdapter(cw, MyMethod.class.getSimpleName());cr.accept(cv, ClassReader.EXPAND_FRAMES);byte[] bytes = cw.toByteArray();outputClazz(bytes);Class<?> clazz = new TestMonitor().defineClass("org.itstack.demo.asm.MyMethod", bytes, 0, bytes.length);Method queryUserInfo = clazz.getMethod("queryUserInfo", String.class);Object obj = queryUserInfo.invoke(clazz.newInstance(), "10001");System.out.println("測試結果:" + obj);}static class ProfilingClassAdapter extends ClassVisitor {public ProfilingClassAdapter(final ClassVisitor cv, String innerClassName) {super(ASM5, cv);}public MethodVisitor visitMethod(int access,String name,String desc,String signature,String[] exceptions) {System.out.println("access:" + access);System.out.println("name:" + name);System.out.println("desc:" + desc);if (!"queryUserInfo".equals(name)) return null;MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);return new ProfilingMethodVisitor(mv, access, name, desc);}}static class ProfilingMethodVisitor extends AdviceAdapter {private String methodName = "";protected ProfilingMethodVisitor(MethodVisitor methodVisitor, int access, String name, String descriptor) {super(ASM5, methodVisitor, access, name, descriptor);this.methodName = name;}@Overrideprotected void onMethodEnter() {mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "nanoTime", "()J", false);mv.visitVarInsn(LSTORE, 2);mv.visitVarInsn(ALOAD, 1);}@Overrideprotected void onMethodExit(int opcode) {if ((IRETURN <= opcode && opcode <= RETURN) || opcode == ATHROW) {mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");mv.visitTypeInsn(NEW, "java/lang/StringBuilder");mv.visitInsn(DUP);mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);mv.visitLdcInsn("方法執行耗時(納秒)->" + methodName+":");mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "nanoTime", "()J", false);mv.visitVarInsn(LLOAD, 2);mv.visitInsn(LSUB);mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(J)Ljava/lang/StringBuilder;", false);mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);}}}}

    整體的代碼塊有點大,我們可以分為塊來看,如下;

  • ClassReader cr = new ClassReader(MyMethod.class.getName());讀取原有類,也是字節碼增強的開始
  • ClassVisitor cv = new ProfilingClassAdapter(cw, MyMethod.class.getSimpleName());開始增強字節碼
  • onMethodEnter,onMethodExit,在方法進入和方法退出時添加耗時執行的代碼。
  • 測試結果:

    直接運行TestMonitor.java;

    access:1 name:<init> desc:()V access:1 name:queryUserInfo desc:(Ljava/lang/String;)Ljava/lang/String; ASM類輸出路徑:/E:/itstack/git/github.com/itstack-demo-asm/itstack-demo-asm-03/target/classes/AsmTestMonitor.class xxxx xxxx xxxx xxxx 方法執行耗時(納秒)->queryUserInfo:132300 測試結果:10001

    八、字節碼控制打印方法的入參

    那么除了可以監控方法的執行耗時,還可以將方法的入參信息進行打印出來。這樣就可以在一些異常情況下,看到日志信息。

    其他代碼與上面相同,這里只列一下修改的地方

    static class ProfilingMethodVisitor extends AdviceAdapter {private String methodName = "";protected ProfilingMethodVisitor(MethodVisitor methodVisitor, int access, String name, String descriptor) {super(ASM5, methodVisitor, access, name, descriptor);this.methodName = name;}@Overrideprotected void onMethodEnter() {mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");mv.visitVarInsn(ALOAD, 1);mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);}@Overrideprotected void onMethodExit(int opcode) {} }

    從這里可以看到,在方法進入時候使用指令碼 GETSTATIC,獲取輸出對象類
    接下來使用 ALOAD,從局部變量1中裝載引用類型值入棧
    最后輸出入參信息

    測試結果:

    直接運行TestMonitor.java;

    Class<?> clazz = new TestMonitor().defineClass("org.itstack.demo.asm.MyMethod", bytes, 0, bytes.length);Method queryUserInfo = clazz.getMethod("queryUserInfo", String.class);Object obj = queryUserInfo.invoke(clazz.newInstance(), "10001");System.out.println("測試結果:" + obj);

    結果;

    access:1 name:<init> desc:()V access:1 name:queryUserInfo desc:(Ljava/lang/String;)Ljava/lang/String; ASM類輸出路徑:/E:/itstack/git/github.com/itstack-demo-asm/itstack-demo-asm-04/target/classes/AsmTestMonitor.class 10001...

    10001 就是我們的方法入參

    九、用字節碼增強調用外部方法

    好!那么執行到這,我們可以想到如果只是將一些信息打印到控制臺還是沒有辦法做業務的,我們需要在這個時候將各種屬性信息調用外部的類,進行發送到服務端。比如使用;mq、日志等。

    定義日志信息輸出類

    public class MonitorLog {public static void info(String name, int... parameters) {System.out.println("方法:" + name);System.out.println("參數:" + "[" + parameters[0] + "," + parameters[1] + "]");}}

    這個類主要模擬字節碼增強后,方法調用輸出一些信息

    增強字節碼

    static class ProfilingMethodVisitor extends AdviceAdapter {private String name;...@Overrideprotected void onMethodEnter() {// 輸出方法和參數mv.visitLdcInsn(name);mv.visitInsn(ICONST_2);mv.visitIntInsn(NEWARRAY, T_INT);mv.visitInsn(DUP);mv.visitInsn(ICONST_0);mv.visitVarInsn(ILOAD, 1);mv.visitInsn(IASTORE);mv.visitInsn(DUP);mv.visitInsn(ICONST_1);mv.visitVarInsn(ILOAD, 2);mv.visitInsn(IASTORE);mv.visitMethodInsn(INVOKESTATIC, "org/itstack/demo/asm/MonitorLog", "info", "(Ljava/lang/String;[I)V", false);} }

    這里的有一部分字節碼操作,其實在增強后最終的效果如下;

    public int sum(int i, int m) {Monitor.info("sum", i, m);return i + m; }

    測試結果:

    access:1 name:sum desc:(II)I signature:null ASM類輸出路徑:/E:/itstack/git/github.com/itstack-demo-asm/itstack-demo-asm-05/target/classes/AsmTestMonitor.class 方法:sum 參數:[6,2] 結果:8

    通過測試內容可以看到,我們已將方法名稱與參數信息打印完整。好!到這我們已經基本入門了 ASM 字節碼編程的大門

    十、總結

    高級編程技術的內容還不止于此,不要只為了一時的功能實現,而放棄深挖深究的機會。也許就是你不斷的增強拓展個人的知識技能,才讓你越來越與眾不同。
    ASM 這種字節碼編程的應用是非常廣的,但可能確實平時看不到的,因為他都是與其他框架結合一起作為支撐服務使用。像這樣的技術還有很多,比如 javaassit、netty等等。
    對于真的要學習一樣技術時,不要只看爽文,但爽文也確實給了你敲門磚。當你要徹底的掌握某個知識的時候,最重要的是成體系的學習!壓榨自己的時間,做有意義的事,是3-7年開發人員最正確的事!
    ————————————————
    版權聲明:本文為CSDN博主「小傅哥」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
    原文鏈接:https://blog.csdn.net/generalfu/article/details/105110600

    總結

    以上是生活随笔為你收集整理的如果你只写CRUD,那这种技术栈你永远碰不到的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 免费黄色片网站 | 黄色免费视频网站 | 国产91精品久久久久久久网曝门 | 丝袜 亚洲 另类 欧美 重口 | 香蕉视频色版 | 国产成人免费 | 夜夜撸影院 | 88av网| 久久这里只有精品9 | 最新中文字幕在线观看 | 天堂一区二区三区 | 国产婷婷色综合av蜜臀av | 香蕉视频官网在线观看 | www.欧美在线 | 91视频网页 | 免费国产黄 | 嫩草午夜少妇在线影视 | 亚洲免费观看高清在线观看 | 亚洲精品一区二区三区中文字幕 | 香蕉视频在线观看黄 | 色翁荡息又大又硬又粗又爽 | 日本一区二区三区在线观看 | 嫩草懂你 | a视频 | 精品少妇久久久久久888优播 | 日本不卡一区在线观看 | 国产一级黄色片子 | 国产三级网站 | 中文字幕av不卡 | 99re6在线精品视频免费播放 | 97香蕉久久超级碰碰高清版 | 97人人模人人爽人人少妇 | 黄色美女一级片 | 午夜精品福利在线观看 | 精品一区二区三区无码按摩 | 亚洲最大在线观看 | 欧美色999| 日韩视频在线观看一区 | 久久久久人妻一区二区三区 | 综合国产视频 | 精品久久久久久久久久久国产字幕 | 永久免费精品影视网站 | 国产美女永久无遮挡 | 色悠悠国产精品 | 先锋av在线资源 | 国产精品传媒一区二区 | 狠狠干天天爱 | 亚洲日批 | 久久久久99精品成人片我成大片 | 国产一区精品在线观看 | 欧美一区二区三区激情 | 中文字幕 视频一区 | 玖草在线视频 | 在线国产精品视频 | 久久精品人妻一区二区 | 成人激情视频网站 | 亚洲一级片 | 九九热这里只有 | 日本黄网在线观看 | 精品一区二区三区免费观看 | 夜夜看av | zzjizzji亚洲日本少妇 | 日日鲁鲁鲁夜夜爽爽狠狠视频97 | 天堂8av| 娇小萝被两个黑人用半米长 | 国产特黄级aaaaa片免 | 伊人久久av | 欧美激情一区二区三区免费观看 | 国产日韩欧美亚洲 | 亚洲激情三区 | 成年人午夜免费视频 | 国产精品第六页 | 日韩欧美国产电影 | 成人手机在线免费视频 | 国产精品欧美一区二区三区 | 一区二区三区久久久久 | 国产精品久久久免费观看 | 欧美黄色影院 | 日韩丰满少妇无码内射 | 中文字幕91爱爱 | 欧美情爱视频 | 欧美成人aaa片一区国产精品 | 中文字幕系列 | 久久久久亚洲av片无码下载蜜桃 | a黄色一级片 | 精品国精品国产自在久不卡 | 国产一级免费 | 爱情岛亚洲论坛入口福利 | 激情小说五月天 | 精品动漫3d一区二区三区免费版 | 99视频 | 黄色日比视频 | 天美乌鸦星空mv | 小小姑娘电影大全免费播放 | 青青草成人免费在线视频 | 国产剧情在线 | 日本黄色网络 | 免费在线观看黄色网址 | 日韩黄色在线播放 |