, 以前一直没觉得,现在发现写博客还是一件蛮有趣的事情, :)
动态代理的实现有两种方式: 一种是jdk的动态代理,实现类必须实现某个接口; 另一种是cglib,使用底层的字节码技术,对实现类没有要求。
首先来看一个简单使用jdk动态代理的例子:
第一步: 定义接口
public interface Animal {
public String getName();
}
第二步:具体实现类
public class Dog implements Animal {
@Override
public String getName() {
System.out.println("***pretty dog***");
return "Dog";
}
}
第三步:实现代理类,代理类需要实现InvocationHandler接口
public class ProxyTest implements InvocationHandler {
private Animal animal;
public ProxyTest(Animal animal) {
super();
this.animal = animal;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("---before method---");
Object obj = method.invoke(animal, args);
System.out.println("---after method---");
return obj;
}
public static void main(String[] args) {
Animal animal = new Dog();
ClassLoader classLoader = animal.getClass().getClassLoader();
Class<?>[] interfaces = animal.getClass().getInterfaces();
InvocationHandler h = new ProxyTest(animal);
Animal proxyAnimal = (Animal) Proxy.newProxyInstance(classLoader, interfaces, h);
proxyAnimal.getName();
}
}
运行上面的代码,输出结果如下:
---before method---
***pretty dog***
---after method---
下面来看下代码的调用过程,在main方法中,调用Proxy.newProxyInstance方法来生成代理对象,code如下:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
/*
* Look up or generate the designated proxy class.
*/
Class cl = getProxyClass(loader, interfaces);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
throw new InternalError(e.toString());
}
}
在newProxyInstance方法中,通过调用getProxyClass方法来获取代理类的class对象,主要代码如下(原方法较长,只是选择了部分关键的code):
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException
{
Map cache;
/*
* 如果已经创建或者正在创建代理对象,则直接返回或者等待创建完成;否则跳出循环
*/
synchronized (cache) {
do {
Object value = cache.get(key);
if (value instanceof Reference) {
proxyClass = (Class) ((Reference) value).get();
}
if (proxyClass != null) {
// proxy class already generated: return it
return proxyClass;
} else if (value == pendingGenerationMarker) {
// proxy class being generated: wait for it
try {
cache.wait();
} catch (InterruptedException e) {
/*
* The class generation that we are waiting for should
* take a small, bounded time, so we can safely ignore
* thread interrupts here.
*/
}
continue;
} else {
/*
* No proxy class for this list of interfaces has been
* generated or is being generated, so we will go and
* generate it now. Mark it as pending generation.
*/
cache.put(key, pendingGenerationMarker);
break;
}
} while (true);
}
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
}
return proxyClass;
}
ProxyGenerator在rt.jar中,需要先下载源码,我是直接使用eclipse 的反编译工具来看。可以参考链接: http://tangmingjie2009.iteye.com/blog/1916992。
最终生成的代理类经反编译之后如下(下面的文件是直接通过调用byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy1", animal.getClass().getInterfaces()) 生成):
public final class $Proxy1 extends Proxy
implements Animal
{
public $Proxy1(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final String getName()
{
try
{
return (String)super.h.invoke(this, m3, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m3;
private static Method m1;
private static Method m0;
private static Method m2;
static
{
try
{
m3 = Class.forName("ss.proxy.Animal").getMethod("getName", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
因此当调用ProxyTest中的getName的方法时,会调用$Proxy1对象的getName方法,然后通过super.h.invoke(this, m3, null)调用ProxyTest的invoke方法,其中参数m3为Dog的getName方法。