JDK动态代理实现
IBuyCar buyCar1=new BuyCarImpl();
IBuyCar buyCarProxy=(IBuyCar)Proxy.newProxyInstance(IBuyCar.class.getClassLoader(),
new Class[]{IBuyCar.class},new DynamicProxyHandler(buyCar1));
buyCarProxy.buyCar("福特");
可以看到newProxyInstance方法有三个参数:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
其中ClassLoader是指定接口类的类加载器,Class<?>[] interfaces是接口类中的接口列表,InvocationHandler 是处理器。
底层原理
一、主要关于InvocationHandler和Proxy,前面看不懂没事,坚持看完你就懂了,我也是这么过来的 InvocationHandler接口
public class DynamicProxyHandler implements InvocationHandler {
private Object obj;
public DynamicProxyHandler(Object obj)
{
this.obj=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
System.out.println("动态代理实现买车前准备");
Object object=method.invoke(obj,args);
System.out.println("动态代理实现买车后");
return object;
}
}
子类重写的时候,需要将具体实现类对象(不是代理类)传递进去,然后用反射调用具体实现类的方法,同时增加其他业务逻辑。
二、Proxy类
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);handler的非空判断
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
Class<?> cl = getProxyClass0(loader, intfs);根据classloader和接口数组生成代理类的class对象
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
获取动态生成的代理类中参数为InvocationHandler的构造方法
//private static final Class<?>[] constructorParams = { InvocationHandler.class };
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
得到cl代理类class中类的修饰符,然后判断是不是public类型,如果是,就返回指定构造器cons的实例,即代理对象的实例,如果不是,就将cons构造方法设置为可访问。
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
1、根据传递进来的ClassLoader,以及我们的代理对象的父接口数组,来动态创建二进制的class文件,然后根据创建好的Class二进制文件,获取到创建的动态代理类的Class对象。
2、通过代理类的class对象,获取class对象中参数为InvocationHandler的构造方法
3、判断构造方法的访问修饰符,如果不是public的,将其设置成可以访问的
4、调用构造器的newInstance方法,参数为InvocationHandler,返回代理类的实例
WeakCache这个对象当中会在get取不到值时,去生成一个值,放入进去;
ProxyClassFactory是Proxy的一个静态内部类,主要就是用来根据classLoader和接口数组来生成Class对象的。
subKeyFactory.apply(key, parameter) 方法调用的是ProxyClassFactory@apply(ClassLoader loader, Class<?>[] interfaces) 方法
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);用来存传入的接口
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
try {
根据接口全限定类名和classLoader,获取到接口class对象
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
如果两次接口class对象不一致,直接抛出异常,说明创建错误
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
判断创建出来的接口是不是接口类型,不是就抛异常
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
判断接口的set集合是否已经存在了该接口类,存在抛出异常,不存在就添加进去
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
判断非public接口是不是在同一个包内,如果不是,抛出异常;
声明代理类所在的包位置,
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
如果都是public接口设定全限定类名com.sun.proxy.$proxy0
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);
try {
根据生成的字节码,创建class对象并返回。Native方法
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
可以看到这段代码就是设置好需要生成的类的类名,然后调用ProxyGenerator.generateProxyClass来生成代理类的字节码
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
//中间省略掉一部分代码
return var4;
}
private byte[] generateClassFile() {
//将object类当中的 hashcode,equals,toString方法添加到动态代理类当中
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();
//检查代理类当中的返回类型
List var12;
while(var11.hasNext()) {
var12 = (List)var11.next();
checkReturnTypes(var12);
}
Iterator var15;
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());
} catch (IOException var10) {
throw new InternalError("unexpected I/O Exception", var10);
}
if(this.methods.size() > '\uffff') {
throw new IllegalArgumentException("method limit exceeded");
} else if(this.fields.size() > '\uffff') {
throw new IllegalArgumentException("field limit exceeded");
} else {
/**
* 省略部分代码
**/
return var13.toByteArray();
} catch (IOException var9) {
throw new InternalError("unexpected I/O Exception", var9);
}
}
}
生成了代理类对象,继承自Proxy,实现了subject接口,其构造方法是传递了InvocationHandler参数,同时实现了equals ,hashcode,toString方法,以及我们自己定义的request方法。
这里就能清楚的看到,代理类中,request方法,其实就是调用InvocationHandler实现类中invoke方法,m3就是RealSubject中定义的request方法
这里就能知道,调用Subject的request的时候,为什么能够调用动态代理类的invoke方法了。因为在调用bind中的Proxy.newProxyInstance的时候,传入的是我们classLoader,代理类的父接口,和自定义的InvocationHandler,因此生成的代理类对象中的h就是自定义的InvocationHandler。
整体流程:
使用方法:
定义一个接口Subject,里面有抽象方法request,一个接口的实现类RealSubject,里面有真正的request方法,定义个ProxyHandler,实现InvocationHandler接口,有ProxyHandler中有个目标对象target,用于传入RealSubject的实例;里面有两个方法,bind方法,将传入的RealSubject对象,赋值给target,并调用Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this)返回代理类对象的实例;还有一个方法,invoke(Object proxy, Method method, Object[] args)方法,在method.invoke前后可以加逻辑功能;method方法对象包含方法的相关信息,method.invoke就会去找target对象中,指定参数与该方法匹配的方法。
底层原理:
首先分析代理对象的产生过程,最后分析代理对象的产生后的样子
产生过程:
Proxy.newInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this) 方法,该方法主要做了
①获取代理类的接口Subject.class对象的副本intfs。
②调用getProxyClass0(loader, intfs)方法,获取代理类的class对象
--2.1 getProxyClass方法会去调用proxyClassCache.get(loader,interfaces)方法,该方法的作用,如果缓存中已经有该接口对应的代理类的副本,那么返回代理类的副本,否则使用ProxyClassFactory的apply方法创建一个class对象;get方法中有一句表现了这个过程,如下图
SubkeyFactory与ProxyClassFactory都是BiFunction接口的的实现类,此处调用的是ProxyClassFactory的apply方法。
----2.1.1 apply方法:根据接口的全限定类名以及指定的classLoader,调用class.forName方法得到接口的class对象interfaceClass,进行判断是否是接口类型,是否有重复,
----2.1.2 设定代理类所在的包路径,如果有非public接口,且不是在同一个包内,抛异常,如果在同一个包内,就设定代理类的包路径为proxyPkg,如果都是public接口,那么生成的代理类的包路径proxyPkg设定为com.sum.proxy.
----2.1.3 根据包路径,类名前缀和num数字,确定代理类的名字
----2.1.4 调用ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);内部生成一个ProxyGenerator对象,调用ProxyGenerator.generateClassFile()得到代理类的字节码文件;
------2.1.4.1 ProxyGenerator.generateClassFile()方法,为代理类添加了三个object类的hashcode,equals,toString方法,遍历父接口,获取每个接口中的方法,添加方法,添加构造方法等,都加入到代理中;返回二进制字节码文件
----2.1.5 调用defineClass0(loader, proxyName, proxyClassFile, 0,proxyClassFile.length);将字节码文件创建为class对象,返回
③获取到代理类的class对象后,得到代理类参数为InvocationHandler的构造方法,如果是非public类型,就使用setAccessible设定为true,然后调用cons.newInstance(new Object[]{h})来生成代理类对象;
④在代理类对象中,有个request方法,方法中默认会调用Proxy类里面的InvocationHandler也就是我们自定义的InvocationHandler的invoke方法。这就实现了动态代理