一个简单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 方法中。

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

(0)

相关推荐

  • Spring AOP注解失效的坑及JDK动态代理

    @Transactional @Async等注解不起作用 之前很多人在使用Spring中的@Transactional, @Async等注解时,都多少碰到过注解不起作用的情况. 为什么会出现这些情况呢?因为这些注解的功能实际上都是Spring AOP实现的,而其实现原理是通过代理实现的. JDK动态代理 以一个简单的例子理解一下JDK动态代理的基本原理: //目标类接口 public interface JDKProxyTestService { void run(); } //目标类 publ

  • Java JDK动态代理的基本原理详细介绍

    JDK动态代理详解 本文主要介绍JDK动态代理的基本原理,让大家更深刻的理解JDK Proxy,知其然知其所以然.明白JDK动态代理真正的原理及其生成的过程,我们以后写JDK Proxy可以不用去查demo,就可以徒手写个完美的Proxy.下面首先来个简单的Demo,后续的分析过程都依赖这个Demo去介绍,例子采用JDK1.8运行. JDK Proxy HelloWorld package com.yao.proxy; /** * Created by robin */ public inter

  • java jdk动态代理详解

    jdk动态代理要对一个类进行代理,被代理的类必须实现至少一个接口,并且只有接口中的方法才能被代理. jdk实现动态代理一般分为三步: 1. 编写接口和实现类. 2. 写一个处理器,该处理器实现InvocationHandler接口,该接口只有一个方法,其签名为public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;可在该处理器的实现方法中,在方法调用前和调用后加入自己的代码,从而进行动态拦截

  • 深入理解java动态代理的两种实现方式(JDK/Cglib)

    什么是代理模式? 代理模式:在调用处不直接调用目标类进行操作,而是调用代理类,然后通过代理类来调用目标类进行操作.在代理类调用目标类的前后可以添加一些预处理和后处理操作来完成一些不属于目标类的功能. 为什么要使用代理模式? 通过代理模式可以实现对目标类调用的控制.在目标类调用前/后进行一些不属于目标类的操作,如:数据验证.预处理.后处理.异常处理等 什么是静态代理什么是动态代理? 静态代理:代理类只能实现对"特定接口的实现类"进行代理 动态代理:代理类可以实现对多种类的代理 jdk代理

  • java动态代理(jdk与cglib)详细解析

    JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,代理类可以分为两种. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经

  • 详解Spring的两种代理方式:JDK动态代理和CGLIB动态代理

    代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用 A. 抽象主题角色 声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以是使用代理主题 B. 代理主题(Proxy)角色: 代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象:代理主题角

  • java代理 jdk动态代理应用案列

    java代理有jdk动态代理.cglib代理,这里只说下jdk动态代理,jdk动态代理主要使用的是java反射机制(既java.lang.reflect包) 原理是(歌手.经纪人做例子): 建立一个公共的接口,比如:歌手public interface Singer: 用具体的类实现接口,比如:周杰伦,他是歌手所以实现Singer这个类,class MySinger implements Singer 建立代理类,这里也就是经纪人,他需要实现InvocationHandler类,并重写invok

  • Java JDK动态代理(AOP)的实现原理与使用详析

    本文主要给大家介绍了关于Java JDK动态代理(AOP)实现原理与使用的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍: 一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 代理模式UML图: 简单结构示意图: 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别.通过代理类这中间一层,能有效控制对委托类对

  • 浅谈Java代理(jdk静态代理、动态代理和cglib动态代理)

    一.代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强.加入一些非业务性代码,比如事务.日志.报警发邮件等操作. 二.jdk静态代理 1.业务接口 /** * 业务接口 * @author pc * */ public interface UserService { // 增加一个用户 public void addUser(); // 编辑账户 public void editUser(); } 2.业务实现类 /** * 业务实现类 * @author pc

  • jdk中动态代理异常处理分析:UndeclaredThrowableException

    背景 在RPC接口调用场景或者使用动态代理的场景中,偶尔会出现UndeclaredThrowableException,又或者在使用反射的场景中,出现InvocationTargetException,这都与我们所期望的异常不一致,且将真实的异常信息隐藏在更深一层的堆栈中.本文将重点分析下UndeclaredThrowableException 先给结论 使用jdk动态代理接口时,若方法执行过程中抛出了受检异常但方法签名又没有声明该异常时则会被代理类包装成UndeclaredThrowableE

随机推荐