您的位置:首页 > 编程语言 > Java开发

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

2017-04-08 22:27 429 查看

现在有一个接口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 源码 动态代理