设计模式之自己实现动态代理

本文基于代理模式,深入分析JDK动态代理的实现原理,包括利用反射获取接口、动态生成新类、添加增强代码等。还介绍了自己实现JDK动态代理的方法,如将生成对象写入磁盘文件、反编译查看类等,最后说明了查看JDK生成代理类的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于前一篇设计模式之代理模式,我们来深入分析下JDK动态代理是如何实现的,并自己实现JDK动态代理。

github代码:github动态代理代码,老铁,如果喜欢可以给看小星星,谢谢。

1、JDK动态代理原理分析

(1)通过被代理对象的引用,利用反射获取所有接口;

(2)通过Proxy类动态生成一个新类,并实现所有接口;

(3)反射调用时将增强的代码添加在被代理类目标方法前后;

(4)编译新生成的java类,并加载到JVM中。

核心类:InvocationHandler、Proxy、ClassLoader。

 

2、自己实现JDK动态代理

(1)首先我们将动态代理生成的对象写入磁盘文件,通过反编译查看生成的类。

package com.william.javacore.pattern.structure.proxy.jdk;

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;

/**
 * @Author: WilliamDream
 * @Description:
 * @Date: 2017/6/22 16:01
 */
public class JdkDynamicProxyTest {

    public static void main(String[] args) {
        try{

            Person obj = (Person)new HouseProxy().getInstance(new Renter());
            System.out.println(obj.getClass());
            obj.findHouse();

            //把动态代理生成的对象写入磁盘文件
            byte [] bytes = ProxyGenerator.generateProxyClass("$proxy0",new Class[]{Person.class});
            FileOutputStream os = new FileOutputStream("D://$proxy0.class");
            os.write(bytes);
            os.close();

        }catch(Exception e){
            e.printStackTrace();
        }
    }

}

(3)反编译后代码

import com.william.javacore.pattern.structure.proxy.jdk.Person;
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 Person
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;

  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 (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final void findHouse()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

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

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    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.william.javacore.pattern.structure.proxy.jdk.Person").getMethod("findHouse", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      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());
  }
}

3、查看JDK生成的代理类

(1)创建接口类MyInvocationHandler

/**
 * @Author: WilliamDream
 * @Description:
 * @Date: 2017/6/22 21:58
 */
public interface MyInvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

(2)创建代理对象

package com.william.javacore.pattern.structure.proxy.myproxy;

import com.william.javacore.pattern.structure.proxy.jdk.Person;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Author: WilliamDream
 * @Description:
 * @Date: 2017/6/22 22:08
 */
public class MyHouseProxy implements MyInvocationHandler{

    //保存被代理对象的引用
    private Object target;

    public Object getInstance(Person object) throws Exception {
        this.target = object;
        Class<?> clazz = target.getClass();
        return MyProxy.newProxyInstance(new MyClassLoader(),clazz.getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.doBefore();
        method.invoke(this.target,args);
        this.doAfter();
        return null;
    }

    private void doBefore(){
        System.out.println("我是房产中介,我们有很多房源。");
    }

    private void doAfter(){
        System.out.println("我带你去看房吧!");
    }

}

(3)创建MyProxy类

package com.william.javacore.pattern.structure.proxy.myproxy;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @Author: WilliamDream
 * @Description: 用于生成代码
 * @Date: 2017/6/22 22:09
 */
public class MyProxy {


    private static final String ln = "\r\n";

    public static Object newProxyInstance(MyClassLoader loader,
                                          Class<?>[] interfaces,
                                          MyInvocationHandler h) {
        try {
            // 1、生成代理类$Proxy0.java
            String codeStr = generateCode(interfaces);
            System.out.println(codeStr);

            //2、Java文件输出到磁盘
            String filepath = MyProxy.class.getResource("").getPath();
            File file = new File(filepath + "$Proxy0.java");
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(codeStr);
            fileWriter.close();

            //3、动态的编译生成的类$Proxy0
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null,null,null);
            Iterable iterable = manager.getJavaFileObjects(file);

            JavaCompiler.CompilationTask task = compiler.getTask(null,null,null,null,null,null);
            task.call();
            manager.close();

            Class proxyClass = loader.findClass("$Proxy0");
            Constructor constructor = proxyClass.getConstructor(MyInvocationHandler.class);

            return constructor.newInstance(h);


        } catch (Exception e){
            e.printStackTrace();
        }

        return null;
    }


    private static String generateCode(Class<?>[] interfaces){

        //生成动态代理产生的类$proxy0的代码
        StringBuffer sb = new StringBuffer();
        sb.append("package com.william.javacore.pattern.structure.proxy.myproxy;" + ln);
        sb.append("import com.william.javacore.pattern.structure.proxy.jdk.Person;" + ln);
        sb.append("import java.lang.reflect.*;" + ln);

        sb.append("public class $Proxy0 implements " + interfaces[0].getSimpleName() + "{" + ln);

        sb.append("private MyInvocationHandler h;" + ln);
        sb.append("public $Proxy0(MyInvocationHandler h) {" + ln);
        sb.append("this.h = h;" + ln);
        sb.append("}" + ln);

        for (Method method : interfaces[0].getMethods()){
            sb.append("public " + method.getReturnType().getName() + " " + method.getName() + "(){" + ln);
            sb.append("try{" + ln);
            sb.append("Method m = " + interfaces[0].getSimpleName() +".class.getMethod(\"" + method.getName() + "\",new Class[]{});" + ln);
            sb.append("this.h.invoke(this,m,null);" + ln);
            sb.append("}catch(Throwable e){" + ln);
            sb.append("e.printStackTrace();" + ln);
            sb.append("}" + ln);
            sb.append("}" + ln);
        }
        sb.append("}" + ln);

        return sb.toString();
    }

}

(4)创建MyClassLoader对象

package com.william.javacore.pattern.structure.proxy.myproxy;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;

/**
 * @Author: WilliamDream
 * @Description:
 * @Date: 2017/6/22 22:08
 */
public class MyClassLoader extends ClassLoader{

    private File classPathFile;

    public MyClassLoader(){
        String classPath = MyClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String className = MyClassLoader.class.getPackage().getName() + "." + name;
        if(classPathFile != null){
            File classFile = new File(classPathFile,name.replace("\\.","/")+".class");
            if (classFile.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try{
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte [] buff = new byte[1024];
                    int len ;
                    while ((len = in.read(buff)) != -1){
                        out.write(buff,0,len);
                    }
                    return  defineClass(className,out.toByteArray(),0,out.size());
                }catch (Exception e){
                    e.printStackTrace();
                }

            }

        }
        return super.findClass(name);
    }
}

(5)测试

package com.william.javacore.pattern.structure.proxy.myproxy;

import com.william.javacore.pattern.structure.proxy.jdk.HouseProxy;
import com.william.javacore.pattern.structure.proxy.jdk.Person;
import com.william.javacore.pattern.structure.proxy.jdk.Renter;
import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;

/**
 * @Author: WilliamDream
 * @Description:
 * @Date: 2017/6/22 22:17
 */
public class MyProxyTest {

    public static void main(String[] args){

        try {
            Person person = new Renter();
            MyHouseProxy houseProxy = new MyHouseProxy();
            Person p = (Person)houseProxy.getInstance(person);
            p.findHouse();

            //把动态代理生成的对象写入磁盘文件
           /* byte [] bytes = ProxyGenerator.generateProxyClass("$proxy0",new Class[]{Person.class});
            FileOutputStream os = new FileOutputStream("D://$proxy0.class");
            os.write(bytes);
            os.close();*/
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

总结:

1、Proxy生成的类以$开头,数字结尾,如果生成代理类有多个,数字自增。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值