本篇文章主要参考了:http://blog.csdn.net/jiankunking/article/details/52143504,这篇文章写的十分详细,收获颇丰,特写这篇博客记录所得
1. 什么是动态代理?
代理不仅出现在代码中,我们的生活中也处处存在着代理的思想,例如房地产代理、各种票务的代理等。代理的思想是形容用户和服务的提供者不是直接接触、相互影响,而是通过中间代理对象去调用服务提供者的具体方法,并加入一些包装或检验行为,最终将服务结果返回给用户。而Java中的动态代理则是对静态代理类的一种升级,使我们不需要为每一个需要被代理的类编写代理类,在运行时为被代理类生成class文件,通过class的实例来实现代理。
2. JDK中的动态代理
JDK中的动态代理的使用主要分为三部分:
1)编写被代理的接口与其实现类; 2)编写InvocationHandler接口的实现; 3)调用Proxy.newProxyInstance()创建代理类的实例。
下面我们通过一个简单的例子(银行提供查询余额、存钱、取钱等操作)来说明JDK中动态代理的使用方法:
- 编写银行bank的接口:
public interface Bank {
public boolean drawMoney(int amount);
public boolean saveMoney(int amount);
public boolean checkBalance();
}
- 编写bank的实现类:
public class BankImpl implements Bank {
@Override
public boolean drawMoney(int amount) {
System.out.println("取出了"+amount+"元");
return true;
}
@Override
public boolean saveMoney(int amount) {
System.out.println("存入了"+amount+"元");
return true;
}
@Override
public boolean checkBalance() {
System.out.println("你的余额为:"+100+"元");
return true;
}
}
- 编写InvocationHandler的实现类:
public class BankInvocationHandler implements InvocationHandler {
private Bank bank;
public BankInvocationHandler(Bank bank) {
this.bank = bank;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("银行执行方法:"+method.getName()+"之前..");
Object result = method.invoke(bank,args);
System.out.println("执行结果为:"+result);
System.out.println("银行执行方法:"+method.getName()+"之后..");
return result;
}
}
- main函数中测试:
public static void main(String[] args) {
Bank bank = new BankImpl();
InvocationHandler invocationHandler = new BankInvocationHandler(bank);
ClassLoader classLoader = bank.getClass().getClassLoader();
Class[] interfaces = bank.getClass().getInterfaces();
Bank bankProxy = (Bank) Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
System.out.println("动态代理类实例:"+bankProxy.getClass().getName());
bankProxy.checkBalance();
}
- 测试结果:
动态代理类实例:com.sun.proxy.$Proxy0
银行执行方法:checkBalance之前..
你的余额为:100元
执行结果为:true
银行执行方法:checkBalance之后..
3.总结
上面的代码虽然简单,但是刚接触反射等概念时对BankInvocationHandler类中的invoke()方法充满疑惑,main函数中的bankProxy.checkBalance()是如何调用到BankInvocationHandler中的方法?
想要搞清楚这些就需要弄清楚动态代理是如何实现的?
首先,回到main函数中的:
Bank bankProxy = (Bank) Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
这个方法用到了代理类Proxy中的newProxyInstance()方法,根据被代理的实现类BankImpl的类加载器、接口数组、自定义的代理处理器实现类创建出一个代理类实例。 但是可能更令人不解的是为什么接下来通过bankProxy.checkBalance()可以调用BankInvocationHandler中的invoke()方法,并且调用的方法checkBalance()可以作为invoke()的形参。
要想知道这其中是如何发生的,需要进入Proxy.newProxyInstance()方法中看一看:
@CallerSensitive
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);
}
/*
* 信息方法,根据类加载器和接口获取代理类
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* 通过反射获取代理类的构造器并创建新实例
*/
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);
}
}
我们发现通过方法:getProxyClass0(loader, intfs)获取到代理类,进入getProxyClass0(loader, intfs):
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
从方法proxyClassCache.get(loader, interfaces)可以看出这个方法是在缓存中查找由loader加载并且实现了接口interfaces定义的代理类,如果没有则通过ProxyClassFactory创建代理类。
如果再往下深究,会在ProxyClassFactory类的apply()方法中找到:
//生成代理类的字节码数组
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
为了弄清是如何代理的,我们可以生成一个字节码文件看一下反编译后的类是什么样的:
private static void createProxyClassFile(){
String name = "ProxySubject";
byte[] data = ProxyGenerator.generateProxyClass(name,new Class[]{Subject.class});
FileOutputStream out =null;
try {
out = new FileOutputStream(name+".class");
System.out.println((new File("hello")).getAbsolutePath());
out.write(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(null!=out) try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
由上面的方法形成的代理类反编译结果如下ProxySubject:
public final class ProxySubject extends Proxy implements Bank {
private static Method m1;
private static Method m5;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public ProxySubject(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 boolean drawMoney(int var1) throws {
try {
return ((Boolean)super.h.invoke(this, m5, new Object[]{var1})).booleanValue();
} 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 boolean checkBalance() throws {
try {
return ((Boolean)super.h.invoke(this, m3, (Object[])null)).booleanValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean saveMoney(int var1) throws {
try {
return ((Boolean)super.h.invoke(this, m4, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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", Class.forName("java.lang.Object"));
m5 = Class.forName("com.kk.proxy.Bank").getMethod("drawMoney", Integer.TYPE);
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.kk.proxy.Bank").getMethod("checkBalance");
m4 = Class.forName("com.kk.proxy.Bank").getMethod("saveMoney", Integer.TYPE);
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
以上的ProxySubject的代码就是:
Bank bankProxy = (Bank) Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
为我们生成的动态代理类bankProxy,所以bankProxy调用checkBalance()方法其实是调用了ProxySubject类中的checkBalance():
public final boolean checkBalance() throws {
try {
//调用BankInvocationHandler的invoke()方法
return ((Boolean)super.h.invoke(this, m3, (Object[])null)).booleanValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
动态生成的ProxySubject代理类中的属性主要就包含了几个实现的方法m1~m6,最下方的静态代码块通过反射进行初始化:
//静态代码块的执行顺序:静态代码块—>非静态代码块—>构造方法(静态代码块只在第一次new执行一次,之后不再执行,而非静态代码块在每new一次就执行一次。)
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m5 = Class.forName("com.kk.proxy.Bank").getMethod("drawMoney", Integer.TYPE);
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.kk.proxy.Bank").getMethod("checkBalance");
m4 = Class.forName("com.kk.proxy.Bank").getMethod("saveMoney", Integer.TYPE);
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}