使用示例
- 定义接口
public interface Subject {
void doSomething();
}
- 定义实现
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject do something");
}
}
- 定义jdk代理
public class JDKDynamicProxy implements InvocationHandler {
private Object target;
public JDKDynamicProxy(Object target) {
this.target = target;
}
/**
* 获取被代理接口实例对象
* @param <T>
* @return
*/
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Do something before");
Object result = method.invoke(target, args);
System.out.println("Do something after");
return result;
}
}
- 调用
public class Client {
public static void main(String[] args) {
// 保存生成的代理类的字节码文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// jdk动态代理测试
Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy();
subject.doSomething();
}
}
我们看到如果使用jdk代理,需要的核心要素有哪些?
1、接口及实现目标类
2、JDK代理类需要实现一个InvocationHandler 接口invoke方法。
这个实现,我们可以看出,是代理了类中所有方法。实现了相同的操作;
那么它的内部实现原理是什么?
原理
- 生成代理对象
//核心实现,生成代理对象。
Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
public class Proxy implements java.io.Serializable {
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
final Class<?>[] intfs = interfaces.clone();
、
/*
* 核心生成代理类
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
*通过handler生成实例
*/
final Constructor<?> cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[]{h});
}
}
- 核心生成代理类,我们可以看到核心只需要相应接口和loader。
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
return proxyClassCache.get(loader, interfaces);
}
// proxyClassCache.get
public V get(K key, P parameter) {
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Factory factory = new Factory(key, parameter, subKey, valuesMap);
return factory.get();
}
// factory.get
public synchronized V get() {
valueFactory.apply(key, parameter)
}
//其中,valueFactory是构造函数中构造的。
public class Proxy {
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
}
final class WeakCache<K, P, V> {
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
BiFunction<K, P, V> valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
this.valueFactory = Objects.requireNonNull(valueFactory);
}
}
//所以valueFactory就是ProxyClassFactory
//继续查看applay方法
// 所有代理类名称前缀为$Proxy
private static final String proxyClassNamePrefix = "$Proxy";
// 全局自增编号,和proxyClassNamePrefix 进行拼接,组成代理类名
private static final AtomicLong nextUniqueNumber = new AtomicLong();
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
//接口校验....
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* 非public接口,代理类的包名与接口的包名相同
*/
for (Class<?> intf : interfaces) {
..
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
*生成代理类名
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* 生成代理类字节码。核心!!!!!
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
}
- 代理类字节码生成。这个是核心类。
这个类的命名空间package sun.misc,是个jdk提供的功能类
public class ProxyGenerator {
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
// 是否要将生成代理类的字节码文件保存到磁盘中
if (saveGeneratedFiles) {
// ....
}
}
//new ProxyGenerator(var0, var1, var2);
private ProxyGenerator(String var1, Class<?>[] var2, int var3) {
this.className = var1;
this.interfaces = var2;
this.accessFlags = var3;
}
//var3.generateClassFile();核心中的核心。
private byte[] generateClassFile() {
//添加了三个方法。这三个方法怎么来的。看下面。
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
//接口也接入
Class[] var1 = this.interfaces;
int var2 = var1.length;
int var3;
Class var4;
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
Method[] var5 = var4.getMethods();
int var6 = var5.length;
for(int var7 = 0; var7 < var6; ++var7) {
Method var8 = var5[var7];
this.addProxyMethod(var8, var4);
}
}
//准备转换字节码
Iterator var11 = this.proxyMethods.values().iterator();
try {
this.methods.add(this.generateConstructor());
var11 = this.proxyMethods.values().iterator();
while(var11.hasNext()) {
var12 = (List)var11.next();
var15 = var12.iterator();
while(var15.hasNext()) {
ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
//核心生成每个方法的字节码
this.methods.add(var16.generateMethod());
}
}
this.methods.add(this.generateStaticInitializer());
}
}
//generateClassFile中的三个添加方法
private static Method hashCodeMethod;
private static Method equalsMethod;
private static Method toStringMethod;
static {
try {
hashCodeMethod = Object.class.getMethod("hashCode", new Class[0]);
equalsMethod = Object.class.getMethod("equals", new Class[]{Object.class});
toStringMethod = Object.class.getMethod("toString", new Class[0]);
} catch (NoSuchMethodException var1) {
throw new NoSuchMethodError(var1.getMessage());
}
}
private ProxyGenerator.MethodInfo generateMethod() throws IOException {
DataOutputStream var9 = new DataOutputStream(var2.code);
ProxyGenerator.this.code_aload(0, var9);
var9.writeByte(180);
var9.writeShort(ProxyGenerator.this.cp.getFieldRef("java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;"));
ProxyGenerator.this.code_aload(0, var9);
var9.writeByte(178);
var9.writeShort(ProxyGenerator.this.cp.getFieldRef(ProxyGenerator.dotToSlash(ProxyGenerator.this.className), this.methodFieldName, "Ljava/lang/reflect/Method;"));
if(this.parameterTypes.length > 0) {
ProxyGenerator.this.code_ipush(this.parameterTypes.length, var9);
var9.writeByte(189);
var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/Object"));
for(int var10 = 0; var10 < this.parameterTypes.length; ++var10) {
var9.writeByte(89);
ProxyGenerator.this.code_ipush(var10, var9);
this.codeWrapArgument(this.parameterTypes[var10], var3[var10], var9);
var9.writeByte(83);
}
} else {
var9.writeByte(1);
}
var9.writeByte(185);
// ...字节流写入操作
}
}
- 生成的代理类
在测试案例中,设置系统属性sun.misc.ProxyGenerator.saveGeneratedFiles值为true
// 保存生成的代理类的字节码文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
判定是否保存
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
// 是否要将生成代理类的字节码文件保存到磁盘中
if (saveGeneratedFiles) {
// ....
}
return var4;
}
打开$Proxy0.class文件如下:
package com.sun.proxy;
import com.example.aop.jdk.Subject;
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 Subject {
private static Method m1;
private static Method m4;
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})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void doSomething() throws {
try {
super.h.invoke(this, m4, (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);
}
}
public final void doSomething1() 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)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m4 = Class.forName("com.example.aop.jdk.Subject").getMethod("doSomething", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.example.aop.jdk.Subject").getMethod("doSomething1", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
1、继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。
2、提供了一个使用InvocationHandler作为参数的构造方法,最终所有方法都是调用此方法。并把真实对象方法传递进来,通过反射调用。
参考资料:
JDK动态代理实现原理
网友评论