JDK动态代理实现原理
JDK动态代理实现原理
动态代理机制
- 通过实现 InvocationHandler 接口创建自己的调用处理器
- 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入
Interface InvocationHandler
该接口中仅定义了一个方法Object:invoke(Object obj,Method method,Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。
Proxy
- 该类即为动态代理类
Protected Proxy(InvocationHandler h)
- 构造函数,用于给内部的h赋值
Static Class getProxyClass (ClassLoader loader,Class[] interfaces)
- 获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组
Static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
- 返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)
Dynamic Proxy
- 它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
代码示例
创建接口
/** * @ClassName: BuyService * @Description: 购买基础接口 * @Author: 尚先生 * @CreateDate: 2019/6/17 14:52 * @Version: 1.0 */
public interface BuyService {
String buyPhone();
String buyComputer();
}
创建实现类
/** * @ClassName: BuyServiceImpl * @Description: 购买实现类 * @Author: 尚先生 * @CreateDate: 2019/6/17 14:53 * @Version: 1.0 */
public class BuyServiceImpl implements BuyService {
@Intercept("buyPhone")
@Override
public String buyPhone() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("==========BuyServiceImpl.class=============" + " buyPhone");
this.buyComputer();
return "buy phone";
}
@Intercept("buyComputer")
@Override
public String buyComputer() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("==========BuyServiceImpl.class=============" + " buyComputer");
return "buy computer";
}
}
创建 InvocationHandler
/** * @ClassName: ReflectionHandler * @Description: 自定义处理handler * @Author: 尚先生 * @CreateDate: 2019/6/17 14:54 * @Version: 1.0 */
public class ReflectionHandler implements InvocationHandler {
private Object target;
public ReflectionHandler(Object target) {
this.target = target;
}
public <T> T getProxy(){
return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target,args);
}
}
创建启动类
/** * @ClassName: Bootstrap * @Description: 启动测试类 * @Author: 尚先生 * @CreateDate: 2019/6/17 14:58 * @Version: 1.0 */
public class Bootstrap {
public static void main(String[] args) {
// 动态代理实现
ReflectionHandler reflectionHandler = new ReflectionHandler(new BuyServiceImpl());
BuyService proxy = reflectionHandler.getProxy();
String computer = proxy.buyComputer();
String phone = proxy.buyPhone();
System.out.println(computer + "\r\n" + phone);
}
运行结果
// 修改前执行结果
========BuyServiceImpl.class=========== buyComputer
========BuyServiceImpl.class=========== buyPhone
=======BuyServiceImpl.class=========== buyComputer
buy computer
buy phone
代理类字节码文件
/** * 代理类字节码文件,反编译结果 * @Author: 尚先生 * @CreateDate: 2019/6/17 14:54 * @Version: 1.0 */
import com.learn.demo.java.proxy.BuyService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class ProxyBuyService
extends Proxy
implements BuyService
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public ProxyBuyService(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 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);
}
}
public final String buyPhone(BuyService paramBuyService)
throws
{
try
{
return (String)this.h.invoke(this, m3, new Object[] { paramBuyService });
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String buyComputer(BuyService paramBuyService)
throws
{
try
{
return (String)this.h.invoke(this, m4, new Object[] { paramBuyService });
}
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);
}
}
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.learn.demo.java.proxy.BuyService").getMethod("buyPhone", new Class[] { Class.forName("com.learn.demo.java.proxy.BuyService") });
m4 = Class.forName("com.learn.demo.java.proxy.BuyService").getMethod("buyComputer", new Class[] { Class.forName("com.learn.demo.java.proxy.BuyService") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
代码流程分析
- 具体的实现流程如同上述代码,创建InvocationHandler对象,根据Proxy创建代理对象,通过代理对象执行目标方法,返回执行结果。
- 从创建接口到默认实现类,我们可以通过直接new 实现类的方式去实现,但是有时候我们比不知道具体实现类是哪个,或者说实现类自身去做会很大程度上增加代码的耦合性。这时候我们采用代理的方式去增强代码的可用性。
以上是JDK动态代理的实际实现,但是在执行结果中看不到buyPhone() 调用buyComputer()的实际调用类信息,实际执行信息打印已经在GitHub中更新,更多详情可关注dwyanewede。
// 修改后的执行结果,详见GitHub
========当前类描述 com.sun.proxy.$Proxy0=========== buyComputer
========当前类描述 com.sun.proxy.$Proxy0=========== buyPhone
=======当前类描述 com.learn.demo.java.proxy.BuyServiceImpl=========== buyComputer
buy computer
buy phone
为什么要关注这一点呢,因为这一点跟我们在Spring Framework框架中一些AOP切面拦截密切相关,具体在Spring Framework框架中的实现,可参见下一篇文章:JDK动态代理在Spring AOP中的实现
更多优秀文章
JDK动态代理在Spring AOP中的实现
https://blog.csdn.net/shang_xs/article/details/92778364
java界的小学生
https://blog.csdn.net/shang_xs
还没有评论,来说两句吧...