java-动态代理-从源码分析

现在有一个接口UserService

public interface UserService {  

/** 
 * 目标方法  
 */  
public abstract void add();  

}  

有一个实现类

public class UserServiceImpl implements UserService {  

/* (non-Javadoc) 
 * @see dynamic.proxy.UserService#add() 
 */  
public void add() {  
    System.out.println("--------------------add---------------");  
}  
}  

有一个InvocationHandler类

public class MyInvocationHandler implements InvocationHandler {  

// 目标对象   
private Object target;  

/** 
 * 构造方法 
 * @param target 目标对象  
 */  
public MyInvocationHandler(Object target) {  
    super();  
    this.target = target;  
}  


/** 
 * 执行目标对象的方法 
 */  
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  

    // 在目标对象的方法执行之前简单的打印一下  
    System.out.println("------------------before------------------");  

    // 执行目标对象的方法  
    Object result = method.invoke(target, args);  

    // 在目标对象的方法执行之后简单的打印一下  
    System.out.println("-------------------after------------------");  

    return result;  
}  
}  

现在就可以实现动态代理啦

public class ProxyTest {  

@Test  
public void testProxy() throws Throwable {  
    // 实例化目标对象  
    UserService userService = new UserServiceImpl();  

    // 实例化InvocationHandler  
    MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);  

    // 根据目标对象生成代理对象,参数为:一个classloader,一个接口数组,一个invocationHandler 
    UserService proxy = (UserService)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),userService.getClass().getInterfaces(), invocationHandler );

    // 调用代理对象的方法  
    proxy.add();  

}  
}  

解析

当你刚看到动态代理时,会感到非常疑惑与混乱。但最终的结果告诉我们,最后执行的代码是invocationHandler.invoke方法:

System.out.println("------------------before------------------");  

    // 执行目标对象的方法  
    Object result = method.invoke(target, args);  

    // 在目标对象的方法执行之后简单的打印一下  
    System.out.println("-------------------after------------------");  

通过查看Proxy.newProxyInstance方法的源码,我发现,有用的就两句话,大概意思是:

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
Class proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
Constructor cons = proxyClass.getConstructor(InvocationHandler.class);
return (Object) cons.newInstance(new Object[] { invocationHandler });

java用Proxy.newInstance的第二个参数:接口数组,构造了一个新的class,并且返回了一个用该class构造的一个新的对象,通过反编译工具,来将该class文件反编译为一个java文件,来看看究竟:

public final class $Proxy11 extends Proxy  implements UserService  

{   
public $Proxy11(InvocationHandler invocationhandler)  
{  
    super(invocationhandler);  
}  

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 void add()  
{  
    try  
    {    
        super.h.invoke(this, m3, null);  
        return;  
    }  
    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 m1;  
private static Method m3;  
private static Method m0;  
private static Method m2;  

static   
{  
    try  
    {  
        m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {  
            Class.forName("java.lang.Object")  
        });  
        m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", new Class[0]);  
        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());  
    }  
}  
}  

也就是说当我们调用proxy.add()方法时,add方法的代码为:
super.h.invoke(this, m3, null);
super.h:
h也就是我们我们构造这个类时传入的参数,上面提到过,具体代码如下:
return (Object) cons.newInstance(new Object[] { invocationHandler });
一个我们定义过的类的实例。
m3:
m3 = Class.forName(“dynamic.proxy.UserService”).getMethod(“add”, new Class[0]);
现在一切就很清晰明了了吧,知其然知其所以然,现在就可以灵活运用java动态代理了。

参考文章:http://rejoy.iteye.com/blog/1627405

你可能感兴趣的:(Java)