动态代理是目前使用的比较广泛技术,大家都比较熟悉的框架比如Spring中的AOP特性就用到了动态代理
比如说有一个业务需要我们在添加或者删除用户的时候,将信息添加到日志当中,但是把日志的代码插入原有的业务代码中是很不雅观的,为了不破坏原有的实现类,这时候我们就可以用到动态代理。
接口类
public interface UserService {
public void add();
public void delete(int id);
}
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("add");
}
@Override
public void delete(int id) {
System.out.println("delete:"+id);
}
}
使用JDK的动态代理首先要实现InvocationHandler接口
package com.zhu.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler{
//用户服务实现类的实例
private Object target;
public MyInvocationHandler(Object target){
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
String name=method.getName();
if("add".equals(name)){
System.out.println("用户添加");
}else if("delete".equals(name)){
System.out.println("用户删除");
}
//真正执行业务的地方
Object result=method.invoke(target, args);
return result;
}
}
main
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 这句设置系统属性,使得JVM产生的代理类都可以保存在文件中 路径为:com/sun/proxy,需要手动的在项目的根目录创建路径,如图
注意生成的为代理类的class文件,此时还需要使用反编译工具(百度一下反编译工具即可下载)将其转换为大家都能看懂的java文件
package com.zhu.proxy.jdk;
import java.lang.reflect.Proxy;
public class TestProxy {
public static void main(String[] args) {
//设置系统属性,使得JVM产生的代理类都可以保存在文件中 路径为:com/sun/proxy
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
UserServiceImpl userService=new UserServiceImpl();
MyInvocationHandler h=new MyInvocationHandler(userService);
//proxy为生成的代理类对象
UserService proxy=(UserService)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),userService.getClass().getInterfaces(),h);
proxy.add();
proxy.delete(1);
}
}
运行结果
package com.sun.proxy;
import com.zhu.proxy.jdk.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0
extends Proxy
implements UserService
{
private static Method m1;
private static Method m3;
private static Method m4;
private static Method m0;
private static Method m2;
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void add()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void delete(int paramInt)
throws
{
try
{
this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt) });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.zhu.proxy.jdk.UserService").getMethod("add", new Class[0]);
m4 = Class.forName("com.zhu.proxy.jdk.UserService").getMethod("delete", new Class[] { Integer.TYPE });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
可以看到代理类中,我们需要被代理的方法add(),和delete()的实现中都是直接调用InvovationHandler中的invoke方法
代理类的生成是由该行代码实现(为了方便理解以下源码为简化后的伪代码,只保留了最重要的部分)
Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),userService.getClass().getInterfaces(),h);
public static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
final Class[] intfs = interfaces.clone();
// 获取代理类的Class对象
Class cl = getProxyClass0(loader, intfs);
//根据参数获取构造函数
final Constructor cons = cl.getConstructor(constructorParams);
//生成代理类的实例
return newInstance(cons, ih);
}
private static Object newInstance(Constructor cons, InvocationHandler h) {
return cons.newInstance(new Object[] {h} );
}
newInstance方法很简单,就是通过反射来实例化对象
在接着看getProxyClass0方法
private static Class getProxyClass0(ClassLoader loader,
Class... interfaces) {
return proxyClassCache.get(loader, interfaces);
}
首先会在缓存中查到是否该类加载器已经加载过该代理类,如果找到则直接返回,否则使用
ProxyClassFactory来生成代理类
public Class apply(ClassLoader loader, Class[] interfaces) {
long num = nextUniqueNumber.getAndIncrement();
//拼接代理类名
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//生成字节码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);
// 通过类加载器生成代理类的Class对象
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
}
到这里相信大家对JDK动态代理的使用和原理也有了一定的了解。