聊聊、动态代理

动态代理大家都不陌生,生活中也有很多动态代理的例子,例如:香港代购。我们只需要说产品名称,代购就可以把产品从香港买回来给我们。

微服务特别火,基本上每个公司都会涉及到。微服务的调用却是离不开 RPC 框架,从 RMI、WEBSERVICE、到今天的 Dubbo、GRPC、Thrift、SpringCloud等等。我们调用远程服务就像是调用本地服务一样,其实这些 RPC 框架给我们做了很多的事情,这些事情对我们来说是透明的。而代理技术,就是这些事情的核心功能。

 

JDK动态代理 


JDK动态代理是 JDK 反射机制实现的,首先实现 InvocationHandler 接口

1.InvocationHandler 

package org.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class JDKProxyInvoker implements InvocationHandler {

private Object object;

public JDKProxyInvoker(Object object) {
this.object = object;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("===invoke before===");
Object result = method.invoke(object, args);
System.out.println("===invoke after===");
return result;
}
}

2.IUser.java

package org.PO;

public interface IUser {
public String sayHello();
}

3.UserImpl.java 

package org.PO;

public class UserImpl implements IUser {

@Override
public String sayHello() {
System.out.println("===sayHello===");
return "UserImpl hello";
}
}

4.Main 

IUser iUser = (IUser) Proxy.newProxyInstance(M.class.getClassLoader(),new Class[]{IUser.class},new JDKProxyInvoker(new UserImpl()));
System.out.println(iUser.sayHello());

5.结果

6.Proxy.newProxyInstance原理 

byte[] b = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{IUser.class});
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream("src/main/java/org/jdkproxy/$Proxy0.class");
outputStream.write(b);
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}

7.$Proxy0.class 

public final class $Proxy0 extends Proxy implements IUser {

private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0; 

static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("org.PO.IUser").getMethod("sayHello");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
} 

public $Proxy0(InvocationHandler var1) throws {
super(var1);
} 

public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} 

public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}

public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} 

public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}

} 

iUser.sayHello() 实质上调用的是 $Proxy0.sayHello() 也就是

public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}

这里其实有一个面试题,问 JDK动态代理为什么是代理接口而不是类呢?public final class $Proxy0 extends Proxy implements IUser ,因为已经继承了 Proxy,而 Java 不能多继承。  

posted @ 2020-04-07 10:44  香农随笔  阅读(156)  评论(0编辑  收藏  举报