一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 詳解java中動態代理實現機制

詳解java中動態代理實現機制

2020-03-23 12:35小眼兒 JAVA教程

這篇文章主要為大家介紹了java中動態代理實現機制的相關資料,需要的朋友可以參考下

代理模式是常用的java設計模式,它的特征是代理類與委托類有同樣的接口,代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后處理消息等。代理類與委托類之間通常會存在關聯關系,一個代理類的對象與一個委托類的對象關聯,代理類的對象本身并不真正實現服務,而是通過調用委托類的對象的相關方法,來提供特定的服務。

JAVA各種動態代理實現的比較

詳解java中動態代理實現機制

接口

?
1
2
3
4
5
6
7
interface AddInterface{
 int add(int a, int b);
}
 
interface SubInterface{
 int sub(int a, int b);
}

實現類

?
1
2
3
4
5
6
7
8
9
10
11
class Arithmetic implements AddInterface, SubInterface{
 @Override
 public int sub(int a, int b) {
  return a-b;
 }
 
 @Override
 public int add(int a, int b) {
  return a+b;
 }
}

方式1: JDK自帶的動態代理

1、實現方式

  Java在JDK1.3后引入的動態代理機制,使我們可以在運行期動態的創建代理類。使用動態代理實現AOP需要有四個角色:被代理的類,被代理類的接口,織入器,和InvocationHandler,而織入器使用接口反射機制生成一個代理類,然后在這個代理類中織入代碼。被代理的類是AOP里所說的目標,InvocationHandler是切面,它包含了Advice和Pointcut。

詳解java中動態代理實現機制

2、vInvocationHandler接口的實現

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class JdkDPQueryHandler implements InvocationHandler{
 private Arithmetic real;
 public JdkDPQueryHandler(Arithmetic real){
  this.real = real;
 }
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  String methodName = method.getName();
  System.out.println(method);
  System.out.println("the method: " + methodName + "開始, 參數: "+Arrays.asList(args));
  Object result = method.invoke(real, args);
  System.out.println("the method: "+methodName+"結束, 結果: " + result);
  return result;
 }
}

3、創建代理類并且調用代理類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main{
 private static int a = 4, b = 2;
 
 public static Object createJDKProxy(Arithmetic real){
  Object proxyArithmetic = Proxy.newProxyInstance(real.getClass().getClassLoader(),
    real.getClass().getInterfaces(), new JdkDPQueryHandler(real));
  return proxyArithmetic;
 }
 
 public static void main(String[] args){
  Arithmetic real = new Arithmetic();
  Object proxyArithmetic = createJDKProxy(real);
  ((AddInterface)proxyArithmetic).add(a, b);
  ((SubInterface)proxyArithmetic).sub(a, b);
 }
}

方式2:動態字節碼生成(cglib)

1、實現方式

  Enhancer和MethodInterceptor。Enhancer可以用來動態的生成一個類,這個類可以繼承指定的一個類,實現指定的一些接口。同時,Enhancer在生成一個類之前需要指定一個Callback,當類方法調用時,方法的執行被分配給這個Callback,MethodInterceptor是一個使用比較多的繼承自Callback的接口,它只有一個方法聲明。

詳解java中動態代理實現機制

2、接口InvocationHandler(jdk中)和接口MethodInterceptor(cglib中)對比

?
1
2
3
4
5
6
public interface MethodInterceptor extends Callback {
 public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}
public interface InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

    從參數構成上,methodInterceptor的輸入參數比Invocationhandler多1個,其實前3個參數對象的含義與Invocationhandler的含義是相同的。
  第一個參數表示調用方法來自哪個對象;
  第二個參數表示調用方法的Method對象;
  第三個參數表示此次調用的輸入參數列表;
  多出來的參數是MethodProxy 類型的,它應該是cglib生成用來代替Method對象的一個對象,使用MethodProxy比調用JDK自身的Method直接執行方法效率會有提升。
3、實現1

MethodInterceptor接口的實現

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class CglibDPQueryInterceptor implements MethodInterceptor{
 private Arithmetic real;
 public CglibDPQueryInterceptor(Arithmetic real){
  this.real = real;
 }
 
 @Override
 public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  String methodName = method.getName();
  System.out.println(method);
  System.out.println("the method: " + methodName + "開始, 參數: "+Arrays.asList(args));
  //Object result = method.invoke(real, args);//兩種方式都是可以得
  Object result = proxy.invoke(real, args);
  System.out.println("the method: "+methodName+"結束, 結果: " + result);
  return result;
 }
}

創建代理類并調用代理類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main{
 private static int a = 4, b = 2;
 public static Object createCglibProxy(Arithmetic real){
   Enhancer enhancer = new Enhancer();
   enhancer.setCallback(new CglibDPQueryInterceptor(real));
   enhancer.setInterfaces(real.getClass().getInterfaces());
   return enhancer.create();
 }
 
 public static void main(String[] args){
  Arithmetic real = new Arithmetic(); 
  Object proxyArithmetic = createCglibProxy(real); 
  ((AddInterface)proxyArithmetic).add(a, b);
  ((SubInterface)proxyArithmetic).sub(a, b);
 }
}

注意了,MethodProxy在對執行函數的時候,提供了2個方法

?
1
2
public Object invoke (Object obj, Object[] args) throws Throwable
public Object invokeSuper(Object obj, Object[] args) throws Throwable

  其中,javadoc上說這個invoke()方法可以用于相同類中的其他對象的方法執行,也就是說這個方法中的obj需要傳入相同一個類的另一個對象(上述方法中就是傳入了Arithmetic類的不同對象),否則會進入無限遞歸循環(測試之后還真是出現了StackOverflowError)。仔細的想一想就會發現,public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)中的target是實現的代理類對象,通過target調用add()方法時會觸發intercept()方法被調用,如果在intercept()方法中再調用method.invoke(target, args),就相當于add()方法中又調用add()方法,導致無限的遞歸循環。但是如果執行method.invoke(real, args)則不會,因為real和target是同一個類不同對象,real是真實邏輯主題,target是真實主題real的代理。

  下面一個例子來模擬一下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
interface SolveInterface{
 void solve();
}
 
class Real implements SolveInterface{
 public void solve(){
  System.out.println("Real Solve!");
 }
}
 
class Target extends Real{
 private Object obj;
 
 public void setObject(Object obj){
  this.obj = obj;
 }
 
 private void invoke(){
  try {
   Method method = SolveInterface.class.getMethod("solve", new Class[]{});
   method.invoke(obj, new Class[]{});
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 public void solve(){
  System.out.println("Target Solve!");
  invoke();
 }
}
?
1
2
3
4
5
6
7
public class Main{public static void main(String[] args) throws Exception{  
    Target target = new Target();
    target.setObject(new Real());//正確
    //target.setObject(target);//發生循環調用
    target.solve();
  }
}

其實Method的invoke()方法會根據obj的類型去調用對應的solve()方法,也就是多態性。

4、實現2

  MethodInterceptor接口的實現

?
1
2
3
4
5
6
7
8
9
10
11
12
13
class CglibDPQueryInterceptor implements MethodInterceptor{
  
  @Override
  public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    String methodName = method.getName();
    System.out.println(method);
    System.out.println("the method: " + methodName + "開始, 參數: "+Arrays.asList(args));
    // 打印類信息 :target.getClass();省略
    Object result = proxy.invokeSuper(target, args);
    System.out.println("the method: "+methodName+"結束, 結果: " + result);
    return result;
  }
}

創建代理類并調用代理類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Main{
  private static int a = 4, b = 2;
public static Object createCglibProxy(){
     Enhancer enhancer = new Enhancer();
     enhancer.setCallback(new CglibDPQueryInterceptor());
     enhancer.setSuperclass(Arithmetic.class);
     return enhancer.create();
  }
  
  public static void main(String[] args){
    Arithmetic real = new Arithmetic();
 
    Object proxyArithmetic = createCglibProxy();
    
    ((AddInterface)proxyArithmetic).add(a, b);
    ((SubInterface)proxyArithmetic).sub(a, b);
  }
}

  注意了,實現2中Enhancer 沒有設置接口,因為設置了Superclass了(也就是代理類的父類是Arithmetic),我們的代理類會繼承它,而Arithmetic已經實現了我們的接口。為了證明這一點,可以在MethodInterceptor的 intercept方法中打印 target.getClass()的類信息,你會發現cglib的兩種方式代理類的父類是不同的。如下:

  實現1:

?
1
public class com.test.Arithmetic$$EnhancerByCGLIB$$4fa786eb extends java.lang.Object

  實現2:

?
1
public class com.test.Arithmetic$$EnhancerByCGLIB$$4fa786eb extends com.test.Arithmetic

方式3:javassist生成動態代理(代理工廠創建 或者 動態代碼創建)  

  Javassist是一個編輯字節碼的框架,可以讓你很簡單地操作字節碼。它可以在運行期定義或修改Class。使用Javassist實現AOP的原理是在字節碼加載前直接修改需要切入的方法。這比使用Cglib實現AOP更加高效,并且沒太多限制,實現原理如下圖:

詳解java中動態代理實現機制

詳解java中動態代理實現機制

實現1:

接口的實現

?
1
2
3
4
5
6
7
8
9
10
11
12
class JavassistDPQueryHandler implements MethodHandler{
 
  @Override
  public Object invoke(Object target, Method method, Method proxy, Object[] args) throws Throwable {
    String methodName = method.getName();
    System.out.println(method);
    System.out.println("the method: " + methodName + "開始, 參數: "+Arrays.asList(args));
    Object result = proxy.invoke(target, args);
    System.out.println("the method: "+methodName+"結束, 結果: " + result);
    return result;
  }
}

創建代理類并調用代理類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Main{
  private static int a = 4, b = 2;
public static Object createJavassistProxy() throws Exception{
    ProxyFactory factory = new ProxyFactory();
    factory.setSuperclass(Arithmetic.class);
    factory.setHandler(new JavassistDPQueryHandler());
    return factory.createClass().newInstance();
  }
  
  public static void main(String[] args) throws Exception{
    Arithmetic real = new Arithmetic();
    
    Object proxyArithmetic = createJavassistProxy();
    
    ((AddInterface)proxyArithmetic).add(a, b);
    ((SubInterface)proxyArithmetic).sub(a, b);
  }
}

注意:MethodHandler接口中invoke方法的定義,如下:

?
1
public Object invoke(Object target, Method method, Method proxy, Object[] args)

method代表調用方法的Method對象,proxy是代理類產生并代替method的對象,否則用method.invoke(target, args)會產生無限循環調用。

實現2:

  javassist使用動態java代碼常見代理過程和前文的方法略有不同。javassist內部可以通過動態java代碼,生成字節碼。這種方式創建的動態代理可以非常靈活,甚至可以在運行時產生業務邏輯。

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//自定義攔截器接口
interface InterceptorHandler {
  
  /**
   * 調用動態代理對象的方法將反射本方法,可在本方法實現中添加類似AOP的事前事后操作,只有在本方法體中加入如下代碼
   * 被代理的方法才會被執行,返回值將返回給代理最后返回給程序
   * @param obj Object 被代理的對象
   * @param method Method 被代理對象的方法
   * @param args Object[] 被代理對象的方法的參數
   * @return Object 被代理對象的方法執行后的返回值
   * @throws Throwable
   */
  public Object invoke(Object obj, Method method, Object[] args) throws Throwable;
}
 
//攔截器的實現
class InterceptorHandlerImpl implements InterceptorHandler{
  @Override
  public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    System.out.println(method);
    System.out.println("the method: " + methodName + "開始, 參數: "+Arrays.asList(args));
    Object result = method.invoke(obj, args);
    System.out.println("the method: "+methodName+"結束, 結果: " + result);
    return result;
  }
}
 
 
class MyProxyImpl {
  /** 動態代理類的類名后綴 */
  private final static String PROXY_CLASS_NAME_SUFFIX = "$MyProxy_";
  /** 攔截器接口 */
  private final static String INTERCEPTOR_HANDLER_INTERFACE = "com.test.InterceptorHandler";
  /** 動態代理類的類名索引,防止類名重復 */
  private static int proxyClassIndex = 1;
   
  /**
   * 暴露給用戶的動態代理接口,返回某個接口的動態代理對象,注意本代理實現需和com.cuishen.myAop.InterceptorHandler攔截器配合
   * 使用,即用戶要使用本動態代理,需先實現com.cuishen.myAop.InterceptorHandler攔截器接口
   * @param interfaceClassName String 要動態代理的接口類名, e.g test.StudentInfoService
   * @param classToProxy String 要動態代理的接口的實現類的類名, e.g test.StudentInfoServiceImpl
   * @param interceptorHandlerImplClassName String 用戶提供的攔截器接口的實現類的類名
   * @return Object 返回某個接口的動態代理對象
   * @throws InstantiationException
   * @throws IllegalAccessException
   * @throws NotFoundException
   * @throws CannotCompileException
   * @throws ClassNotFoundException
   * @see com.cuishen.myAop.InterceptorHandler
   */
  public static Object newProxyInstance(String interfaceClassName, String classToProxy, String interceptorHandlerImplClassName) throws InstantiationException, IllegalAccessException, NotFoundException, CannotCompileException, ClassNotFoundException {
    Class interfaceClass = Class.forName(interfaceClassName);
    Class interceptorHandlerImplClass = Class.forName(interceptorHandlerImplClassName);
    return dynamicImplementsInterface(classToProxy, interfaceClass, interceptorHandlerImplClass);
  }
   
  /**
   * 動態實現要代理的接口
   * @param classToProxy String 要動態代理的接口的實現類的類名, e.g test.StudentInfoServiceImpl
   * @param interfaceClass Class 要動態代理的接口類, e.g test.StudentInfoService
   * @param interceptorHandlerImplClass Class 用戶提供的攔截器接口的實現類
   * @return Object 返回某個接口的動態代理對象
   * @throws NotFoundException
   * @throws CannotCompileException
   * @throws InstantiationException
   * @throws IllegalAccessException
   */
  private static Object dynamicImplementsInterface(String classToProxy, Class interfaceClass, Class interceptorHandlerImplClass) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException {
    ClassPool cp = ClassPool.getDefault();
    String interfaceName = interfaceClass.getName();
    //動態指定代理類的類名
    String proxyClassName = interfaceName + PROXY_CLASS_NAME_SUFFIX + proxyClassIndex++;
    //要實現的接口的包名+接口名
    String interfaceNamePath = interfaceName;
     
    CtClass ctInterface = cp.getCtClass(interfaceNamePath);
    CtClass cc = cp.makeClass(proxyClassName);
    cc.addInterface(ctInterface);
    Method [] methods = interfaceClass.getMethods();
    for(int i = 0; i < methods.length; i++) {
      Method method = methods[i];
      dynamicImplementsMethodsFromInterface(classToProxy, cc, method, interceptorHandlerImplClass, i);
    }
    return (Object)cc.toClass().newInstance();
  }
   
  /**
   * 動態實現接口里的方法
   * @param classToProxy String 要動態代理的接口的實現類的類名, e.g test.StudentInfoServiceImpl
   * @param implementer CtClass 動態代理類的包裝
   * @param methodToImpl Method 動態代理類里面要實現的接口方法的包裝
   * @param interceptorClass Class 用戶提供的攔截器實現類
   * @param methodIndex int 要實現的方法的索引
   * @throws CannotCompileException
   */
  private static void dynamicImplementsMethodsFromInterface(String classToProxy, CtClass implementer, Method methodToImpl, Class interceptorClass, int methodIndex) throws CannotCompileException {
    String methodCode = generateMethodCode(classToProxy, methodToImpl, interceptorClass, methodIndex);
    CtMethod cm = CtNewMethod.make(methodCode, implementer);
    implementer.addMethod(cm);
  }
   
  /**
   * 動態組裝方法體,當然代理里面的方法實現并不是簡單的方法拷貝,而是反射調用了攔截器里的invoke方法,并將接收到的參數進行傳遞
   * @param classToProxy String 要動態代理的接口的實現類的類名, e.g test.StudentInfoServiceImpl
   * @param methodToImpl Method 動態代理類里面要實現的接口方法的包裝
   * @param interceptorClass Class 用戶提供的攔截器實現類
   * @param methodIndex int 要實現的方法的索引
   * @return String 動態組裝的方法的字符串
   */
  private static String generateMethodCode(String classToProxy, Method methodToImpl, Class interceptorClass, int methodIndex) {
    String methodName = methodToImpl.getName();
    String methodReturnType = methodToImpl.getReturnType().getName();
    Class[] parameters = methodToImpl.getParameterTypes();
    Class[] exceptionTypes = methodToImpl.getExceptionTypes();
    StringBuffer exceptionBuffer = new StringBuffer();
    //組裝方法的Exception聲明
    if(exceptionTypes.length > 0) exceptionBuffer.append(" throws ");
    for(int i = 0; i < exceptionTypes.length; i++) {
      if(i != exceptionTypes.length - 1) exceptionBuffer.append(exceptionTypes[i].getName()).append(",");
      else exceptionBuffer.append(exceptionTypes[i].getName());
    }
    StringBuffer parameterBuffer = new StringBuffer();
    //組裝方法的參數列表
    for(int i = 0; i < parameters.length; i++) {
      Class parameter = parameters[i];
      String parameterType = parameter.getName();
      //動態指定方法參數的變量名
      String refName = "a" + i;
      if(i != parameters.length - 1) parameterBuffer.append(parameterType).append(" " + refName).append(",");
      else parameterBuffer.append(parameterType).append(" " + refName);
    }
    StringBuffer methodDeclare = new StringBuffer();
    //方法聲明,由于是實現接口的方法,所以是public
    methodDeclare.append("public ").append(methodReturnType).append(" ").append(methodName).append("(").append(parameterBuffer).append(")").append(exceptionBuffer).append(" {\n");
    String interceptorImplName = interceptorClass.getName();
    //方法體
    methodDeclare.append(INTERCEPTOR_HANDLER_INTERFACE).append(" interceptor = new ").append(interceptorImplName).append("();\n");
    //反射調用用戶的攔截器接口
    methodDeclare.append("Object returnObj = interceptor.invoke(Class.forName(\"" + classToProxy + "\").newInstance(), Class.forName(\"" + classToProxy + "\").getMethods()[" + methodIndex + "], ");
    //傳遞方法里的參數
    if(parameters.length > 0) methodDeclare.append("new Object[]{"); 
    for(int i = 0; i < parameters.length; i++) {
      //($w) converts from a primitive type to the corresponding wrapper type: e.g.
      //Integer i = ($w)5;
      if(i != parameters.length - 1) methodDeclare.append("($w)a" + i + ",");
      else methodDeclare.append("($w)a" + i);
    }
    if(parameters.length > 0) methodDeclare.append("});\n");
    else methodDeclare.append("null);\n");
    //對調用攔截器的返回值進行包裝
    if(methodToImpl.getReturnType().isPrimitive()) {
      if(methodToImpl.getReturnType().equals(Boolean.TYPE)) methodDeclare.append("return ((Boolean)returnObj).booleanValue();\n");
      else if(methodToImpl.getReturnType().equals(Integer.TYPE)) methodDeclare.append("return ((Integer)returnObj).intValue();\n");
      else if(methodToImpl.getReturnType().equals(Long.TYPE)) methodDeclare.append("return ((Long)returnObj).longValue();\n");
      else if(methodToImpl.getReturnType().equals(Float.TYPE)) methodDeclare.append("return ((Float)returnObj).floatValue();\n");
      else if(methodToImpl.getReturnType().equals(Double.TYPE)) methodDeclare.append("return ((Double)returnObj).doubleValue();\n");
      else if(methodToImpl.getReturnType().equals(Character.TYPE)) methodDeclare.append("return ((Character)returnObj).charValue();\n");
      else if(methodToImpl.getReturnType().equals(Byte.TYPE)) methodDeclare.append("return ((Byte)returnObj).byteValue();\n");
      else if(methodToImpl.getReturnType().equals(Short.TYPE)) methodDeclare.append("return ((Short)returnObj).shortValue();\n");
    } else {
      methodDeclare.append("return (" + methodReturnType + ")returnObj;\n");
    }
    methodDeclare.append("}");
    System.out.println(methodDeclare.toString());
    return methodDeclare.toString();
  }
   
}
 
public class Main{  
  public static void main(String[] args) throws Exception{ 
     //分別對應 代理類要實現的接口類名, 需要代理類的類名, 用戶自定義攔截器實現類的類名
    Object proxyArithmetic = MyProxyImpl.newProxyInstance("com.test.ArithmeticInterface", "com.test.Arithmetic",
                                    "com.test.InterceptorHandlerImpl");
    ((ArithmeticInterface)proxyArithmetic).add(a, b);
    ((ArithmeticInterface)proxyArithmetic).sub(a, b);   
  }
}

打印一下動態實現接口的代碼如下:

?
1
2
3
4
5
6
7
8
9
10
public int add(int a0,int a1) {
com.test.InterceptorHandler interceptor = new com.test.InterceptorHandlerImpl();
Object returnObj = interceptor.invoke(Class.forName("com.test.Arithmetic").newInstance(), Class.forName("com.test.Arithmetic").getMethods()[0], new Object[]{($w)a0,($w)a1});
return ((Integer)returnObj).intValue();
}
public int sub(int a0,int a1) {
com.test.InterceptorHandler interceptor = new com.test.InterceptorHandlerImpl();
Object returnObj = interceptor.invoke(Class.forName("com.test.Arithmetic").newInstance(), Class.forName("com.test.Arithmetic").getMethods()[1], new Object[]{($w)a0,($w)a1});
return ((Integer)returnObj).intValue();
}

以上就是關于java中動態代理實現機制的詳細介紹,希望對大家的學習有所幫助。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 91精品国产91久久久久 | ysl蜜桃色成人麻豆 youwu在线影院 | 湿好紧太硬了我太爽了 | japan在线观看 | 91国产在线播放 | 把女的下面扒开添视频 | 欧美日韩在线观看一区二区 | 黑人巨| 亚洲国产精品高清在线 | 草逼网站视频 | 99精品在线免费 | 亚洲国产成人综合 | 国产精品亚洲片在线va | a色在线 | 精品一久久香蕉国产线看播放 | 973影院| 青青草99热久久 | 日韩a无吗一区二区三区 | 国产成人精品一区二区阿娇陈冠希 | 成人天堂入口网站 | 我和老丈洗澡同性 | 岛国a香蕉片不卡在线观看 荡女淫春2古装 | 国产精品久久久久久福利 | 奇米影视在线视频8888 | 久久久久久久99精品免费观看 | 视频在线播放 | 亚洲国产精品综合福利专区 | 九色PORNY真实丨国产免费 | 欧美一级特黄特色大片免费 | 成人啪啪漫画羞羞漫画www网站 | 男人j放进女人的p免费看视频 | 国产三级精品91三级在专区 | porno中国xxxxx| 四虎精品视频在线永久免费观看 | 草草影院永久在线观看 | 日韩亚洲国产激情在线观看 | 亚洲系列第一页 | 天天摸天天爽视频69视频 | 丝袜捆绑调教丨vk | 美女机巴| 成人影院免费看 |