`
pi88dian88
  • 浏览: 40078 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

浅析jdk动态代理

    博客分类:
  • Java
阅读更多

酷, 以前一直没觉得,现在发现写博客还是一件蛮有趣的事情, :)

 

动态代理的实现有两种方式: 一种是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方法。

 

 

 

 

 

 

 

0
5
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics