通过一个计算器的实现来简单描述JDK动态代理的作用和原理。
- 接口
public interface ICalculator {
int add(int a, int b);
}
- 实现类
public class Calculator implements ICalculator {
@Override
public int add(int a, int b) {
int result = a+b;
return result;
}
}
然而,如果想要在add方法执行时添加一些日志信息,我们就必须在实现类中增加代码量,例如:
public class Calculator implements ICalculator {
@Override
public int add(int a, int b) {
System.out.println(this.getClass().getName()+":The add method begins.");
System.out.println(this.getClass().getName()+":Parameters of the add method: ["+a+","+b+"]");
int result = a+b;
System.out.println(this.getClass().getName()+":Result of the add method:"+result);
System.out.println(this.getClass().getName()+":The add method ends.");
return result;
}
}
并且如果想要添加减法,乘法,除法等功能以及对应的日志信息则实现类中的代码量会非常之多,其中很多代码都是重复的,因此我们利用JDK动态代理来完成代码复用:
package com.jd.calculator;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
static Calculator target;
static InvocationHandler handler = new InvocationHandler() {
/**
* 代理对象的工作
* proxy为动态代理对象
* method为接口中定义的抽象方法
* args为方法参数列表
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println(this.getClass().getName()+":The "+name+" method begins.");
System.out.println(this.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
Object result =method.invoke(target, args);
//根据calculatorProxy.add(1, 2);的add方法名来找到Calculator中的method对象,也就是说在此完成对目标方法的调用
System.out.println(this.getClass().getName()+":Result of the "+name+" method:"+result);
System.out.println(this.getClass().getName()+":The "+name+" method ends.");
return result;
}
};
public static ICalculator getProxy(Calculator target) {
ProxyFactory.target = target;
ClassLoader classLoader = target.getClass().getClassLoader();//代理对象由哪一个类加载器负责加载
Class<?>[] interfaces = target.getClass().getInterfaces();// 代理对象所实现的接口,代理对象与目标对象都要实现的接口
return (ICalculator) Proxy.newProxyInstance(classLoader, interfaces, handler);// 创建代理对象
}
}
上面代码为目标对象创建代理对象,ctrl+点击newProxyInstance找到该方法的源码:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)//loader为类加载器,interfaces为代理对象需要实现的接口数组。
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();//interfaces克隆给intfs
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);//此步骤为使用类加载器,和接口数组来创建实现接口的代理类,
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);//获取代理类的构造方法
final InvocationHandler ih = h;//将我们书写的匿名内部类传给ih
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});//调用代理类的构造方法,并且传入参数ih来创建对象
} 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);
}
}
我们执行测试代码:
import com.jd.calculator.Calculator;
import com.jd.calculator.ICalculator;
import com.jd.calculator.ProxyFactory;
public class Test {
public static void main(String[] args) {
//最终目标,执行new Calculator()对象中的add方法
ICalculator calculatorProxy = ProxyFactory.getProxy(new Calculator());
//获取new Calculator()对象的代理对象
calculatorProxy.add(1, 2);
}
}
执行结果:
此时我们要在计算器中添加功能只需要在接口和实现类中添加:
//接口
public interface ICalculator {
int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b);
}
//实现类
public class Calculator implements ICalculator {
@Override
public int add(int a, int b) {
int result = a+b;
return result;
}
@Override
public int sub(int a, int b) {
int result = a-b;
return result;
}
@Override
public int mul(int a, int b) {
int result = a*b;
return result;
}
@Override
public int div(int a, int b) {
int result = a/b;
return result;
}
}
下面我们分析Test类中的calculatorProxy.add(1, 2);执行过程。
首先我们在Test类中添加
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
来生成使用JDK创建动态代理对象的class文件。注意:该行代码必须放在代理对象产生之前。
之后反编译生成的class文件,查看源代码:
package com.sun.proxy;
import com.jd.calculator.ICalculator;
import java.lang.reflect.*;
public final class $Proxy0 extends Proxy implements ICalculator {
public $Proxy0(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 String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Error _ex) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int add(int i, int j) {
try {
return ((Integer) super.h.invoke(this, m3, new Object[] { Integer.valueOf(i), Integer.valueOf(j) })).intValue();
} 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);
}
}
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.jd.calculator.ICalculator").getMethod("add",new Class[] { Integer.TYPE, Integer.TYPE });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
显然该内部类实现了add方法,在执行 calculatorProxy.add(1, 2);时首先执行内部类中的add方法返回((Integer) super.h.invoke(this, m3, new Object[] { Integer.valueOf(i), Integer.valueOf(j) })).intValue();
实际上是ProxyFactory.handler.invoke(calculatorProxy,method,Object[]{1,2}),在执行到Object result =method.invoke(target, args);时开始调用目标对象的方法,接着继续执行calculatorProxy.add至执行完成。