代理分为静态代理和动态代理两种,静态代理就是在代理类内部保存被代理类的属性,直接调用,这种方式很直接,但不易扩展,如果被代理类方法很多且不断增加,那么代理类也要跟着修改,不灵活。
这里主要说动态代理,其实说动态代理的文章很多了,本文主要是对比下动态生成的代理类,然后给出生成动态代理类的代码片段,给一种直观的展示。
有两种动态代理方式:jdk提供的动态代理和cglib,前者是根据接口生成代理类,生成的代理类实现了提供的接口;后者是实现了被代理类的子类,因此被代理类不能为final,而且必须有无参构造函数。
jdk动态代理需要写一个实现InvocationHandler(目的是实现invoke方法)的代理类(以下称Agency),注意Agency不是最后生成的动态代理类,动态代理类是Proxy.newProxyInstance过程中生成的,newProxyInstance方法会根据动态代理类返回一个实例对象,动态代理类的主要思想是调用agency 对象(Agency类的实例)的invoke方法,在此方法中去反射调用被代理对象的方法,增加附加处理。
上代码:
interface Subject{
void doSomething();
}
interface DupSubject{
void doSomethingAgain();
}
class Real implements Subject,DupSubject{
public void doSomething(){
System.out.println("=========Real doSomething=========");
}
@Override
public void doSomethingAgain() {
System.out.println("=========Real doSomethingAgain=========");
}
}
class Agency implements InvocationHandler{
private Real sub;
public Object bind(Real sub){
this.sub = sub;
Object obj = Proxy.newProxyInstance(Test.class.getClassLoader(), sub.getClass().getInterfaces(), this);
return obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("+++++++++Agency begin+++++++");
method.invoke(sub, args);
System.out.println("+++++++++Agency end+++++++");
return null;
}
}
public class Test{
public static void main(String[] args){
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Agency agency = new Agency();
Real real = new Real();
Object obj = agency.bind(real);
Subject sub = (Subject)(obj);
sub.doSomething();
DupSubject dubSub = (DupSubject)(obj);
dubSub.doSomethingAgain();
}
}
程序输出内容为:
+++++++++Agency begin+++++++
=========Real doSomething=========
+++++++++Agency end+++++++
+++++++++Agency begin+++++++
=========Real doSomethingAgain=========
+++++++++Agency end+++++++
上生成的动态代理类:
final class $Proxy0 extends Proxy
implements Subject, DupSubject
{
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch (Error ) { }
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void doSomething()
{
try
{
super.h.invoke(this, m3, null);
return;
}
catch (Error ) { }
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch (Error ) { }
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void doSomethingAgain()
{
try
{
super.h.invoke(this, m4, null);
return;
}
catch (Error ) { }
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch (Error ) { }
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m3 = Class.forName("Subject").getMethod("doSomething", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("DupSubject").getMethod("doSomethingAgain", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
}
catch (NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch (ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
动态代理类如何生成的具体参照ProxyGenerator generateClassFile方法,默认添加equals/hashcode/toString方法,看这个方法可以充分理解class文件的组成,即常量池、字段表、方法表等。