代理是指一个包装了真实访问对象的类,以便控制对真实类的访问
访问流程如下
public interface SubjectInterface {
void hi();
}
public class RealSubject implements SubjectInterface {
@Override
public void hi() {
System.out.print("hi");
}
}
public class SubjectProxy implements SubjectInterface{
private RealSubject r;
public SubjectProxy() {
r=new RealSubject();
}
@Override
public void hi() {
System.out.println("proxy");
r.hi();
}
}
public class Client {
public static void main(String[] args) {
SubjectInterface subject = new SubjectProxy();
subject.hi();
}
}
复制代码
此时RealSubject作为代理对象的一个属性字段,在运行之前就会生成RealSubject的字节码文件,这种方式也称作静态代理
动态代理
被代理的类在运行时动态生成的,编译的时候并没有生成RealSubject
使用JDK实现动态代理
jdk实现动态代理必须有实现接口InvocationHandler的处理类,用于执行被代理类的方法
public class SubjectInvocationHandler implements InvocationHandler {
private Object myproxy;
public SubjectInvocationHandler(Object proxy) {
this.myproxy = proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invocation handler");
method.invoke(myproxy,args);
return null;
}
}
复制代码
客户端通过使用
java.lang.reflect.Proxy
自行创建代理,然后调用目标方法即可
public class Client {
public static void main(String[] args) {
//classloader会被用来验证是否可以加载传入的接口,
SubjectInterface proxy = (SubjectInterface) Proxy.newProxyInstance(SubjectInterface.class.getClassLoader()
, new Class[]{SubjectInterface.class}
, new SubjectInvocationHandler(new RealSubject()));
proxy.hi();
}
复制代码
访问流程如下
生成代理proxy class阶段
代理对象会在内部缓存,如果没有缓存则会由
ProxyClassFactory
新生成。
首先会做接口校验,比如是否可以从提供的classLoader获取接口
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
复制代码
验证完毕后,会读取接口的class文件使用的是
ProxyGenerator.generateProxyClass
,可以看到它会对整个的class文件的字节做读取
private byte[] generateClassFile() {
...
dout.writeInt(0xCAFEBABE);
...
}
复制代码
最后调用native方法生成代理对象,并存入缓存
获取proxy的构造函数
构造函数指定的参数就是InvocationHandler
创建实例
调用构造函数,传入自定义的invocationHandler,自此生成了一个proxy实例,且实例本身会实现传入的接口,代码实例生成的对象如下所示
public final class $Proxy0 extends Proxy implements SubjectInterface {
...
public final void hi() throws {
try {
//这里的h即Proxy中的InvocationHandler,也就是用户自定义的InvocationHanlder
//这个this对象代表的也就是 $Proxy0 本身
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
...
}
复制代码