基本代码实现
首先jdk的动态代理代理的对象一定需要实现一个或多个接口。
代理接口
public interface Say {
public void say();
}
代理接口实现类
public class User implements Say{
@Override
public void say() {
System.out.println("hello");
}
}
代理接口拦截器
public class UserHandle implements InvocationHandler {
private Say user = null;
public UserHandle(Say user){
this.user = user;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//注释内容后面会说明
/*Class<?> aClass = proxy.getClass();
for (Class<?> anInterface : aClass.getInterfaces()) {
System.out.println(anInterface.getName());
}
System.out.println(aClass.getSuperclass());*/
method.invoke(user, args);
return null;
}
}
创建代理对象
public static void main(String[] args) {
Say user = new User();
UserHandle userHandle =new UserHandle(user);
Say o = (Say) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), userHandle);
o.say();
//System.out.println(user.getClass().getClassLoader().equals(new String("hello").getClass().getClassLoader()));
//System.out.println(new String("hello").getClass().getClassLoader());
//generatorProxy();
}
代码原理剖析
1. 如何生成代理对象
通过调用 Proxy 类里面的静态方法 :
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
返回一个代理类。
1.1 newProxyInstance方法参数解读
第一个参数:ClassLoader load ,需要传入一个类加载器,可通过
类名.class.getClassLoader()获得,实例化类.getClass().getClassLoader()获得。类加载器最好用代理的类获取,上面的例子我用的是代理类获取的(user) 。
补充一点:通过我们自己编写的类去获取的 类加载器 都是 app类加载器
这里我们可以看到获得的类加载器都是同一个加载器,所以第一个参数也可以填 通过其他自己创建的类 获取的类加载器,自己可尝试。原因是jvm底层有三个类加载器,app类加载器 是专门用于加载我们自己创建的类,其他两个类加载器是用来加载 jdk 自己底层的类。具体关于类加载器可自行查找资料。
第二个参数:Class<?>[] interfaces ,需要代理的接口,通过:
类实例.getClass().getInterfaces() 或 类.class().getInterfaces() 获得。
第三个参数:InvocationHandler h 这里通过实现 InvocationHandler接口,并实现其 invoke()方法,在将 实例 传入其中。
2. invoke() 方法解读
public Object invoke(Object proxy, Method method, Object[] args)
第一个参数:Object proxy :生成的代理对象,及上面我的例子 o 。
Say o = (Say) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), userHandle);
为什呢?
我们可通过这段代码获取 jdk 创建的代理对象模板
public static void generatorProxy(){
byte[] $Proxy0s = ProxyGenerator.generateProxyClass("$Proxy0", User.class.getInterfaces());
try (FileOutputStream fileOutputStream = new FileOutputStream(new File("target\\classes\\com\\proxytest\\$Proxy0.class"))){
fileOutputStream.write($Proxy0s);
fileOutputStream.flush();
} catch (Exception e) {
return;
}
}
文件地址自己可修改,是生成的字节码文件所在地址。得到的字节码文件:
import com.proxytest.Say;
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 Say {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
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 void say() throws {
try {
super.h.invoke(this, m3, (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);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.proxytest.Say").getMethod("say");
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 final class $Proxy0 extends Proxy implements Say {
当调用say()方法的时候
public final void say() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
会调用invoke()方法,传入的第一个参数为自己本身,super.h 获得对象为我们自己创建的 实现了 InvocationHandle的对象 ,因为其继承了Proxy类,创建代理对象时将其放入了进去。
通过下面代码可加以验证:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class<?> aClass = proxy.getClass();
for (Class<?> anInterface : aClass.getInterfaces()) {
System.out.println(anInterface.getName());
}
System.out.println(aClass.getSuperclass());
method.invoke(user, args);
return null;
}
结果:
可见其父类和接口与其上相吻合。
第二个参数:Method method : 为代理的方法,代理对象调用的是哪个方法,则传入的是那个方法
例如:我写的例子调用的是 say()方法,当调用方法时传入的参数 m3:
是通过静态代码块初始化而来:
获得代理接口的say()方法。
第三个参数:Object[] args :放传入的参数
最后,希望各位能给个免费的赞 ^-^ ,给作者一点鼓励。