一个简单JDK版动态代理

 更新时间:2019年09月23日 10:38:28   作者:$码出未来  
这篇文章主要为大家详细介绍了一个简单JDK版动态代理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了手动实现的一个简单JDK版动态代理,供大家参考,具体内容如下

一.实现步骤

1.根据目标类的接口类型生成代理类的java文件。
2.编译代理类java文件为.class字节码文件。
3.将编译好的字节码文件加载到jvm中。
4.生成代理类对象并返回。

二.代码实现

1.Proxy类

public class CLProxy  {
  private static final String ENTER= "\r\n";
  private static final String PAKAGE=CLProxy.class.getPackage().toString()+";";
  private static final String CLASS_NAME="$Proxy";
  private static final AtomicInteger NUMBER= new AtomicInteger(0);
  public static Object newProxyInstance(CLClassLoader classLoader, Class<?>[] interfaces,CLInvocationHandler h) throws Exception{
    String className =CLASS_NAME+NUMBER.getAndIncrement();
    //遍历所有的接口生成java 文件
    String javaString = createJavaString(interfaces, className);
    String parentPath = CLProxy.class.getResource("").getPath();
    File file =new File(parentPath,className+".java" );
    FileWriter writer  = new FileWriter(file);
    writer.write(javaString);
    writer.flush();
    writer.close();
    //System.out.println(file);
    //编译
    JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null);
    Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file);
    JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
    task.call();
    standardFileManager.close();
    //创建实例
    Class<?> aClass = classLoader.findClass(className);
    Constructor<?> constructor = aClass.getConstructor(CLInvocationHandler.class);
    Object instance = constructor.newInstance(h);
    //file.delete();
    return instance;
  }
 
  /**
   * 生成java 文件
   * @param interfaces
   * @return
   */
  private static String createJavaString(Class<?>[] interfaces , String className ){
 
    StringBuffer buffer  = new StringBuffer();
    buffer.append(PAKAGE+ENTER);
    buffer.append("import java.lang.reflect.Method;"+ ENTER);
 
    StringBuffer interfaceString= new StringBuffer();
    int length= interfaces.length;
    for (int i = 0; i<length ; ++i){
      interfaceString.append(interfaces[i].getName());
      if (i!=length-1){
        interfaceString.append(",");
      }
    }
    buffer.append("public final class ");
    buffer.append(className);
    buffer.append(" implements ");
    buffer.append(interfaceString);
    buffer.append(" {"+ENTER);
    buffer.append("private CLInvocationHandler handler;"+ENTER);
    buffer.append("public "+className+"(CLInvocationHandler handler) {"+ENTER);
    buffer.append(" this.handler= handler;"+ENTER);
    buffer.append("}"+ENTER);
    for (int i =0 ;i<length;++i){
      Class<?> clazz= interfaces[i];
      Method[] methods = clazz.getMethods();
      for (Method method : methods){
        String returnTypeString = method.getReturnType().getName();
 
        Class<?>[] parameterTypes = method.getParameterTypes();
        StringBuffer paramTypeString = new StringBuffer();
        StringBuffer methodParamString = new StringBuffer();
        StringBuffer invokeParamString = new StringBuffer();
 
        paramTypeString.append("new Class[]{");
        int paramLength= parameterTypes.length;
        for (int j =0 ; j<paramLength ;++j){
          Class<?> paramClazz= parameterTypes[j];
          paramTypeString.append(paramClazz.getName()+".class");
          String paramFieldName = "var"+j;
          methodParamString.append(paramClazz.getName() +" "+paramFieldName);
          invokeParamString.append(paramFieldName);
          if (j!= paramLength-1){
            paramTypeString.append(",");
            methodParamString.append(",");
            invokeParamString.append(",");
          }
        }
        paramTypeString.append("}");
        int modifiers = method.getModifiers();
        if (Modifier.isPublic(modifiers)){
          buffer.append("public");
        }else if (Modifier.isPrivate(modifiers)){
          buffer.append("private");
        }else if (Modifier.isProtected(modifiers)){
          buffer.append("protected");
        }
        buffer.append(" final "+returnTypeString+" "+ method.getName()+"("+methodParamString+"){"+ ENTER);
          buffer.append("try{"+ENTER);
 
        buffer.append("Method method = "+clazz.getName()+".class.getMethod(\""+method.getName()+"\","+paramTypeString+" );"+ENTER);
 
          if (!"void".equals(returnTypeString)){
            buffer.append("return ("+returnTypeString+")");
 
          }
          if (invokeParamString.toString().length()==0){
            invokeParamString.append("null");
          }else{
            invokeParamString = new StringBuffer("new Object[]{"+invokeParamString.toString()+"}");
          }
          buffer.append("this.handler.invoke(this,method,"+invokeParamString+");"+ENTER);
          buffer.append("}catch(Throwable e){"+ENTER);
          buffer.append("e.printStackTrace();"+ENTER);
          buffer.append("}"+ENTER);
          if (!"void".equals(returnTypeString)){
            buffer.append("return null;"+ENTER);
          }
        buffer.append("}"+ENTER);
      }
    }
 
    buffer.append("}");
    return buffer.toString();
  }
 
  public static void main(String[] args) throws Exception {
    Person person = (Person)CLProxy.newProxyInstance(new CLClassLoader(), XiaoMing.class.getInterfaces(), new CLInvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
 
        Object result= method.invoke(new XiaoMing(), args);
        System.out.println("after");
        return result;
      }
    });
    String laoxu = person.call("laoxu");
    System.out.println(laoxu);
    /* person.eat();
    Class<?>[] interfaces = person.getClass().getInterfaces();
    for (Class<?> in:interfaces){
      System.out.println(in.getName());
    }
*/
    Person person2= (Person)CLProxy.newProxyInstance(new CLClassLoader(), XiaoMing.class.getInterfaces(), new CLInvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
 
        Object result= method.invoke(new XiaoMing(), args);
        System.out.println("after");
        return result;
      }
    });
 
    System.out.println(person2.getClass());
 
  }
}

2.InvocationHandler接口

public interface CLInvocationHandler {
 
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable;
 
}

3.ClassLoader类加载器

public class CLClassLoader extends ClassLoader {
 
  private File classPathFile;
 
  public CLClassLoader(){
 
    String classPath = CLClassLoader.class.getResource("").getPath();
 
    this.classPathFile= new File(classPath);
  }
 
 
  @Override
  protected Class<?> findClass(String name) throws ClassNotFoundException {
 
 
    String className = CLClassLoader.class.getPackage().getName()+"."+name;
 
 
 
    if (classPathFile!= null ){
 
 
      File classFile = new File(classPathFile, name.replace("\\.", "/") + ".class");
 
 
      if (classFile.exists()){
 
 
        FileInputStream inputStream =null;
 
        ByteArrayOutputStream outputStream = null;
        try{
          inputStream=new FileInputStream(classFile);
 
          outputStream= new ByteArrayOutputStream();
 
          byte[] bytes = new byte[1024];
          int len;
          while ((len=inputStream.read(bytes))!=-1){
            outputStream.write(bytes,0,len);
          }
          return defineClass(className,outputStream.toByteArray(),0,outputStream.size());
        }catch (Exception e){
          e.printStackTrace();
        }finally {
          if (inputStream!= null){
            try {
              inputStream.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
          if (outputStream!=null){
            try {
              outputStream.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        }
 
 
 
      }
 
 
 
 
    }
    return super.findClass(name);
  }
}

4.测试使用的接口与目标类

//测试使用的接口
public interface Person {
 
  void eat();
 
  String call(String name);
}
 
 
//测试使用目标类
public class XiaoMing implements Person {
  @Override
  public void eat() {
    System.out.println("吃东西");
  }
 
  //@Override
  public String call(String name) {
    return name;
  }
}

注意测试方法在CLProxy 的main 方法中。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot+ThreadLocal+AbstractRoutingDataSource实现动态切换数据源

    SpringBoot+ThreadLocal+AbstractRoutingDataSource实现动态切换数据源

    最近在做业务需求时,需要从不同的数据库中获取数据然后写入到当前数据库中,因此涉及到切换数据源问题,所以本文采用ThreadLocal+AbstractRoutingDataSource来模拟实现dynamic-datasource-spring-boot-starter中线程数据源切换,需要的朋友可以参考下
    2023-08-08
  • java使用common-fileupload实现文件上传

    java使用common-fileupload实现文件上传

    这篇文章主要为大家详细介绍了java使用common-fileupload实现文件上传的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • IntelliJ IDEA本地代码覆盖后恢复原来的代码图解

    IntelliJ IDEA本地代码覆盖后恢复原来的代码图解

    今天小编就为大家分享一篇关于IntelliJ IDEA本地代码覆盖后恢复原来的代码图解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • swing中Tree与滚动条用法实例分析

    swing中Tree与滚动条用法实例分析

    这篇文章主要介绍了swing中Tree与滚动条用法,以实例形式分析了java基于swing实现图形界面的使用技巧,需要的朋友可以参考下
    2015-09-09
  • Java实现飞机大战-连接数据库并把得分写入数据库

    Java实现飞机大战-连接数据库并把得分写入数据库

    这篇文章给大家分享了Java实现飞机大战中连接数据库并把得分写入数据库的相关知识点和代码,有兴趣的可以学习参考下。
    2018-07-07
  • Spring Data JPA 在 @Query 中使用投影的方法示例详解

    Spring Data JPA 在 @Query 中使用投影的方法示例详解

    这篇文章主要介绍了Spring Data JPA 在 @Query 中使用投影的方法,大家需要注意如果要在 @Query 中使用投影,必须要主动声明要查询的字段,并且主动写明字段的别名才行,本文通过sql代码给大家介绍的非常详细,需要的朋友参考下吧
    2022-07-07
  • Java 深入探究讲解抽象工厂模式

    Java 深入探究讲解抽象工厂模式

    当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式,抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态
    2022-04-04
  • javaWEB实现相册管理的简单功能

    javaWEB实现相册管理的简单功能

    这篇文章主要介绍了javaWEB实现相册管理的简单功能,包括图片的上传、统一浏览、单个下载、单个删除,还有一个功能只能删除自己上传的文件,感兴趣的小伙伴们可以参考一下
    2015-11-11
  • Java OpenCV图像处理之自定义图像滤波算子

    Java OpenCV图像处理之自定义图像滤波算子

    这篇文章主要为大家介绍了如何利用Java OpenCV实现自定义图像滤波(降噪) 算子,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编学习一下
    2022-02-02
  • Java Spring boot实现生成二维码

    Java Spring boot实现生成二维码

    大家好,本篇文章主要讲的是Java Spring boot实现生成二维码,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-02-02

最新评论