Java实现动态代理,主要需要三个角色

1、被代理的接口以及代理接口的具体实现类

interface Interface {
    void sayHello();

    void sayBye();
}
class InterfaceImpl implements Interface {

    @Override
    public void sayHello() {
        System.out.println("hello");
    }

    @Override
    public void sayBye() {
        System.out.println("bye");
    }
}

2、用于处理具体代理逻辑的InvocationHandler

class ProxyInvocationHandler implements InvocationHandler {

    private Object instance;

    public ProxyInvocationHandler(Object instance) {
        this.instance = instance;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("start proxy for method " + method.getName());
        method.invoke(instance, args);
        System.out.println("end proxy for method " + method.getName());
        return null;
    }
}

3、Proxy工厂类

Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, invocationHandler);

 

具体调用方法如下

public class ProxyDemo {

    public static void main(String[] args) {
        System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        InterfaceImpl target = new InterfaceImpl();
        ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(target);
        Interface i = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, invocationHandler);
        i.sayHello();
        i.sayBye();
    }

}

 

Java动态代理的实现方式是,根据Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)的前两个参数动态生成代理类,并InvocationHandler做为构造参数,传给生成的Proxy实例

可以通过配置System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");设置将生成的class类写入文件,代理类由sun.misc.ProxyGenerator生成

 

Proxy生成的代理类反编译后的代码如下

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

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

public final class $Proxy0 extends Proxy implements Interface {
private static Method m3;
private static Method m1;
private static Method m4;
private static Method m0;
private static Method m2;

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 void sayBye() throws {
try {
super.h.invoke(this, m4, (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);
}
}

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);
}
}

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

 

Proxy在加载代理类时,使用了两层的缓存,一层是基于classloader的缓存,缓存了不同的classloader,而基于不同的classloader,会缓存已经生成的代理类,缓存的key基于newInstance方法中传入的interfaces而生成

生成Key的逻辑如下

        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
            switch (interfaces.length) {
                case 1: return new Key1(interfaces[0]); // the most frequent
                case 2: return new Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new KeyX(interfaces);
            }
        }

而Key1,Key2,KeyX中则重写了对应的equals方法来区分是否相同

此外,如果在代理的接口中,存在内部接口,即不是申明为public的接口,那么Proxy生成的类的包名会是内部接口所处的包,如果实现的接口全部是public的,则会使用默认包名com.sun.proxy,同时生成的类名为Proxy+序列号,序列号由AtomicLong生成

posted on 2020-01-20 15:40  yytxdy  阅读(134)  评论(0编辑  收藏  举报