首页 > 编程 > Java > 正文

一个简单JDK版动态代理

2019-11-26 08:33:31
字体:
来源:转载
供稿:网友

本文实例为大家分享了手动实现的一个简单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 方法中。

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表