JDK Proxy动态代理原理解析

JDK Proxy动态代理原理解析

准备条件

什么是代理?

什么是静态代理?

什么是动态代理?

动态代理实现的原理又是什么呢?

接口类

// MethodInterface
public interface MethodInterface {
    void saveData();
}

目标类

package com.niit.a04;

public class TargetMethodInterface implements MethodInterface{
    @Override
    public void saveData() {
        System.out.println("我是saveData");
    }
}

一、代理模式的简单实现

package com.niit.a04;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TestProxyMain {

    public static void main(String[] args) {

        TargetMethodInterface targetMethodInterface = new TargetMethodInterface(); // 被代理的目标对象
      
        MethodInterface methodInterface = (MethodInterface) Proxy.newProxyInstance(TestProxyMain.class.getClassLoader(),new Class[]{MethodInterface.class} , new InvocationHandler() { //创建代理对象。第一个参数是类加载器、第二个参数是代理对象所实现的接口。第三个参数为代理增强
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              //代理类本身 ,要执行的代理方法、代理方法的参数
                System.out.println("方法增强");
                Object result = method.invoke(targetMethodInterface, args);
                System.out.println("方法增强后");
                return result ;
            }
        });
        System.out.println(methodInterface.getClass());
        methodInterface.saveData();
    }	
}

二、静态代理

2.1 静态代理的实现

​ 静态代理要和目标类实现相同的接口。第二代理要要拥有目标类的对象

// 代理类要实现相同的接口
package com.niit.a04;
public class ProxyMethodInterface implements MethodInterface {
    TargetMethodInterface targetMethodInterface ;
    public ProxyMethodInterface(TargetMethodInterface targetMethodInterface) {
        this.targetMethodInterface = targetMethodInterface;
    }
    @Override
    public void saveData() {
        //方法增强前逻辑
        System.out.println("方法增强前......");
        this.targetMethodInterface.saveData();
        System.out.println("方法增强后......");
        //方法增强后的逻辑
    }
}

​ 通过上面的代码,可以看出实现静态代理,具有一下几个缺点。

  • 代理类必须持有目标类的实例。为了实现目标类的目标方法的增强,代理类必须有用目标类的实例,以便在增强后调用目标类相同的方法,实现原有的功能。
  • 扩展性差。静态代理要为每一个需要代理的目标对象,创建一个类。扩展性不够好。

三、手动编写动态代理类

3.1 代理类的特点

  1. 首先代理类需要和目标类实现相同的接口。这样,才能和目标类具有相同的方法签名等,实现代理的目标。
  2. 代理类,要将代理的逻辑释放出来。由具体的代理类实例来实现。

3.2 实现方法

3.2.1 定义增强逻辑接口

package com.niit.a04;

import java.lang.reflect.Method;

public interface MethodInvokeHandler {


  /**
    第一个参数表示,要被增强的目标类的具体方法
    第二个参数表示方法的参数
  **/
    Object invoke(Method method,Object[] args);
}

3.2.2 创建代理类

package com.niit.a04;

import java.lang.reflect.Method;

public class ProxyMethod implements MethodInterface {
    //增强逻辑处理器
    private MethodInvokeHandler handler;
    private static Method saveData;
    public ProxyMethod(MethodInvokeHandler handler) {
        this.handler = handler;
    }
    @Override
    public void saveData() {
        //根据传入的逻辑执行增强逻辑
        handler.invoke(saveData, null);
    }
    static {
        try {
            //获取该接口的所有方法
            saveData = MethodInterface.class.getMethod("saveData", new Class[0]);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

3.3 JDK代理类

​ jdk的动态代理,实际上是通过字节码技术,动态的编写代理类,然后生成该代理类的实例。该实例作为Proxy.newProxyInstance方法返回给当前创建代理的对象。

​ 借助于Arthas工具。可以带到源代码为:

MethodInterface methodInterface = (MethodInterface) Proxy.newProxyInstance(TestProxyMain.class.getClassLoader(),new Class[]{MethodInterface.class} , new InvocationHandler() {
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("方法增强");
    Object result = method.invoke(targetMethodInterface, args);
    System.out.println("方法增强后");
    return result ;
  }
});

​ 生成的代理类的源码如下:

package com.niit.a04;


import com.niit.a04.MethodInterface;

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 //继承了Proxy类
        implements MethodInterface { //实现了目标类的接口
    private static Method m1; //获取接口的所有方法,并将其定义成静态变量。这样每次调用的时候就不用重复的使用反射方法来获取具体的方法了。
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    public final boolean equals(Object object) {
        try {
            return (Boolean) this.h.invoke(this, m1, new Object[]{object});
        } catch (Error | RuntimeException throwable) {
            throw throwable;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString() {
        try {
            return (String) this.h.invoke(this, m2, null);
        } catch (Error | RuntimeException throwable) {
            throw throwable;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    /**
     * 实现接口类的具体方法
     */
    public final void saveData() {
        try {
            this.h.invoke(this, m3, null);
            return;
        } catch (Error | RuntimeException throwable) {
            throw throwable;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode() {
        try {
            return (Integer) this.h.invoke(this, m0, null);
        } catch (Error | RuntimeException throwable) {
            throw throwable;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    static { //静态代码块记载接口类的所有方法
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.niit.a04.MethodInterface").getMethod("saveData", new Class[0]);
            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());
        }
    }
}


版权声明:本文为hanxirensheng原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>