jdk的动态代理实现是常用的方法之一,动态代理相比较于静态代理的好处不言而喻,可以少写大量的代理类,更加便于扩展。下面用一个样例来看一下具体实现:
1. 由于实现原理要求,首先需要一个接口
public interface OrderService {
/**
* 添加一个订单
* @param o
*/
void add(Order o);
/**
* 删除一个订单
* @param orderNo
*/
void delete(String orderNo);
}
public class Order {
private String orderNo;
private String orderName;
public Order(String orderNo, String orderName) {
super();
this.orderNo = orderNo;
this.orderName = orderName;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[orderNo=");
builder.append(orderNo);
builder.append(", orderName=");
builder.append(orderName);
builder.append("]");
return builder.toString();
}
}
2. 接口实现
public class OrderServiceImpl implements OrderService {
@Override
public void add(Order o) {
System.out.println("add a order" + o.toString());
}
@Override
public void delete(String orderNo) {
System.out.println(String.format("delete a order[orderNo=%s]", orderNo));
}
}
3. 创建代理工厂
public class OrderProxyFactory implements InvocationHandler {
private Object target;
public OrderProxyFactory(Object target) {
super();
this.target = target;
}
/**
* 获取代理类
* @return $Proxy0对象
*/
@SuppressWarnings("unchecked")
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
/**
* 添加代理方法的额外信息
* proxy $Proxy0对象
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("order handler before...");
Object result = method.invoke(target, args);
// 这样会出现死循环
// Object result = method.invoke(proxy, args);
System.out.println("order handler after...");
return result;
}
}
4.测试
public static void main(String[] args) {
// 代理类的字节码内容保存在了项目根目录下
// System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
OrderProxyFactory orderProxyFactory = new OrderProxyFactory(new OrderServiceImpl());
OrderService orderServiceProxy = orderProxyFactory.getProxy();
System.out.println(orderServiceProxy.getClass());
orderServiceProxy.add(new Order("111", "手机"));
orderServiceProxy.delete("111");
}
输出:
class com.sun.proxy.$Proxy0
order handler before...
add a order[orderNo=111, orderName=手机]
order handler after...
order handler before...
delete a order[orderNo=111]
order handler after...
5. 原理分析
重点在于Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法,方法实现如下:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 1.会根据传入的interfaces生成代理类
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 2.获取实现类的构造函数
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
// 3.实例化代理类,注意此处会将传入的h(OrderProxyFactory实例)保存到实例中
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
从方法实现中可以知道,该方法会生成一个OderService接口的实现类,并生成该类一个实例,注意该实例保存了OrderProxyFactory实例,通过设置环境变量"sun.misc.ProxyGenerator.saveGeneratedFiles",可以得到生成的代理类如下:
public final class $Proxy0 extends Proxy implements OrderService {
private static final long serialVersionUID = -6310918168123410007L;
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public $Proxy0(InvocationHandler var1) {
super(var1);
}
public final boolean equals(Object var1) {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void add(Order var1) {
try {
// 1. 此处会调用InvocationHandler(传入的OrderProxyFactory)的invoke方法
// 2. 此处的this就是$Proxy0实例
// 3. 从下面静态代码块中可以知道m3就是add方法
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void delete(String var1) {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.core.proxy.jdk.OrderService").getMethod("add",
Class.forName("com.core.proxy.jdk.Order"));
m4 = Class.forName("com.core.proxy.jdk.OrderService").getMethod("delete",
Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
从上面生成的代理类就可以清楚的知道JDK动态代理的实现关键之处就是生成了指定接口的实现类,也就可以知道JDK的这种实现为什么必须要有一个接口的原因,还是对于新手来说上面可能出现的死循环的原因,至于怎么生成的$Proxy0的代理类(利用ProxyGenerator),感兴趣的同学可以去研究一下