之前虽然会用JDK的动态代理,但是有些问题却一直没有搞明白。比如说:InvocationHandler的invoke方法是由谁来调用的,代理对象是怎么生成的,直到前几个星期才把这些问题全部搞明白了。
废话不多说了,先来看一下JDK的动态是怎么用的
Java代码
package dynamic.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 实现自己的InvocationHandler
* @author zyb
* @since 2012-8-9
*
*/
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;
}
/**
* 获取目标对象的代理对象
* @return 代理对象
*/
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(), this);
}
}
package dynamic.proxy;
/**
* 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口
* @author zyb
* @since 2012-8-9
*
*/
public interface UserService {
/**
* 目标方法
*/
public abstract void add();
}
package dynamic.proxy;
/**
* 目标对象
* @author zyb
* @since 2012-8-9
*
*/
public class UserServiceImpl implements UserService {
/* (non-Javadoc)
* @see dynamic.proxy.UserService#add()
*/
public void add() {
System.out.println("--------------------add---------------");
}
}
package dynamic.proxy;
import org.junit.Test;
/**
* 动态代理测试类
* @author zyb
* @since 2012-8-9
*
*/
public class ProxyTest {
@Test
public void testProxy() throws Throwable {
// 实例化目标对象
UserService userService = new UserServiceImpl();
// 实例化InvocationHandler
MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
// 根据目标对象生成代理对象
UserService proxy = (UserService) invocationHandler.getProxy();
// 调用代理对象的方法
proxy.add();
}
}
执行结果如下:
------------------before------------------
--------------------add---------------
-------------------after------------------
用起来是比较简单,但是如果能知道它背后做了些什么手脚,那就更好不过了。首先来看一下JDK是怎样生成代理对象的。既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么?
/**
* loader:类加载器
* interfaces:目标对象实现的接口
* h:InvocationHandler的实现类
*/
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 {
// 调用代理对象的构造方法(也就是$Proxy0(InvocationHandler h))
Constructor cons = cl.getConstructor(constructorParams);
// 生成代理类的实例并把MyInvocationHandler的实例传给它的构造方法
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());
}
}
生成的代理类实际上是这样子的:
package spring.agent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import spring.agent.UserService;
public final class $Proxy11 extends Proxy implements UserService {
/**
*
*/
private static final long serialVersionUID = 1L;
public $Proxy11(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
public final void add() {
try {
this.h.invoke(this, Class.forName("spring.agent.UserService").getMethod("add", new Class[0]), null);
return;
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
}
我们也可以直接这样调用:
@Test
public void testContrustor() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
UserService userService = new UserServiceImpl();
// 实例化InvocationHandler
MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
$Proxy11 profx = new $Proxy11(invocationHandler);
profx.add();
}
Java将代理生成的类存在硬盘的操作
package spring.agent;
import java.lang.reflect.Proxy;
import org.junit.Test;
import java.io.FileOutputStream;
import java.io.IOException;
import sun.misc.ProxyGenerator;
public class ProxyGeneratorUtils {
/**
* 把代理类的字节码写到硬盘上
*
* @param path
* 保存路径
*/
public static void writeProxyClassToHardDisk(String proxyClassName) {
String filePath = "D:/aclLog/" + proxyClassName + ".class";
byte[] classFile = ProxyGenerator.generateProxyClass(proxyClassName, UserServiceImpl.class.getInterfaces());
FileOutputStream out = null;
try {
out = new FileOutputStream(filePath);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void testProx() {
ProxyGeneratorUtils.writeProxyClassToHardDisk("UserServiceProxy");
}
}
所以针对以上操作,我们也可以直接写一个代理操作类,来专门进行调用:
@Test
public void testContrustor() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
UserService userService = new UserServiceImpl();
// 实例化InvocationHandler
MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
//Proxy11为自定义或者生成的代理类
$Proxy11 profx = new $Proxy11(invocationHandler);
profx.add();
}
$Proxy11自定义的代理类的内容为:
package spring.agent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import spring.agent.UserService;
public final class $Proxy11 extends Proxy implements UserService {
private static final long serialVersionUID = 1L;
public $Proxy11(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
public final void add() {
try {
this.h.invoke(this, Class.forName("spring.agent.UserService").getMethod("add", new Class[0]), null);
return;
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
}