网上很多文章都将jdk动态代理于反射连接起来,甚至很多文章都说 采用反射生成jdk动态代理
。 这也让我深信不疑,认为jdk的动态代理类就是反射生成的。知道有一天,字节跳动的面试官问我
面试官:动态代理的代理类是怎么生成的?
我:反射(毫不犹豫)
面试官:是吗?
我:啊,不是吗?(懵了)
其实jdk动态代理类是由asm生成的,反射只是在整个动态代理中起到了辅助的作用。
JDK的动态代理中哪里使用了反射
动态代理都是一般这样写:
public static void main(String[] args) {
Tank tank = new Tank();
Movable m = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader(),// 这里用到了反射
new Class[]{Movable.class} ,// 这里用到了反射 //tank.class.getInterfaces()
new TimeProxy(tank)
);
m.move();
}
}
也可以这样写:这样写是比较原始的方式:
public static void main(String[] args) {
Tank tank = new Tank();
// 直接创建一个动态代理类
Class proxyClass = Proxy.getClass(Tkan.class.getClassLoader(), new Class[] {Movable.class}); // 使用到了反射
// 获取代理类proxyClass中带有InvocationHandler的构造器
Constructor ctor = proxyClass.getConstructor(new Class[ InvocationHandler.class]); // 使用到了反射
//调用构造器的newInstance方法创建动态代理实例
Movable timeProxy = (Movable) ctor.newInstance(new Object[] {new TimeProxy(tank)}); // 使用到了反射
timeProxy.move();
}
}
其实 Proxy.newProxyInstance 就是这个逻辑:
private static final Class<?>[] constructorParams =
{ InvocationHandler.class };
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
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);
}
}
asm
但正在创建代理类是这一行代码:
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
我们可以看到 生成代理类使用的根本不是反射,而使用的是ASM
JDK动态代理执行过程
其实,反射只能读取字节码,它没有能力来修改或者创建一个新的类,所以JDK的代理类并不是反射生成的。
实际上,JDK的代理类是ASM生成的,包括cglib也是使用asm。
asm是一个包,这个包非常的小,只有30-50k,比其他的包要小许多,这个包可以修改字节码,有了这个包之后java猜能称之为动态语言。
java.lang.instrument 也有asm的功能,而且它更加强大,因为ASM是一个包,你只能调它提供的API,它有的功能没有,而instrument则是更原始的,但是要使用instrument更加的难,它要求使用者能够读懂字节码中的每一个1 0.
静态代理与动态代理的区别
- 静态代理时在代码中写死的,而动态代理则是在代码运行的过程中动态生成的。
- 由这一点就可一引发很多问题:由于写死在代码里,一个静态代理的一个代理类只能代理一个类(静态代理一般采用实现接口在完成,当然也可以使用继承来完成),会导致我们需要实现很多的代理类
- 同时,如果一个被代理对象希望被多个代理类代理,
- 同时这多个代理类对增强被代理类方法的先后顺序不同会导致结果不同等
这上面几种情况都是静态代理解决不了的。