zoukankan      html  css  js  c++  java
  • 简单实现动态代理(Proxy)

      最近学习了Jdk的动态代理,然后自己也简单的手写了一个。
      
      思路:
          1.根据代理的接口,生成对应的Java代码文件
          2.将生成的Java文件编译成class文件
          3.利用URLClassLoader加载class到Jvm中,利用反射在new出这个对象。


    代理业务接口
    package com.michael.pl;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public interface InvocationHandler {
    
        Object invock(Object object, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException;
    
    }
    
    
    

    需要代理的接口

    
    
    package com.michael.pl.service;
    
    public interface LogService {
    
        void sayHi() throws Exception;
    
        Object out(String text) throws Exception;
    
    }
    
    
    package com.michael.pl.service.impl;
    
    import com.michael.pl.service.LogService;
    
    public class LogServiceImpl implements LogService {
    
        @Override
        public void sayHi() {
    
            System.out.println("hello");
    
        }
    
        @Override
        public Object out(String text) {
            return text;
        }
    }
    
    
    
    实现动态代理的核心类
    package com.michael.pl;
    
    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.Method;
    import java.net.URL;
    import java.net.URLClassLoader;
    
    public class MyProxy {
    
        public static final String TABLE = "    ";
        public static final String ENTER = "
    ";
    
        public static Object newProxyInstance(ClassLoader classLoader, Class<?> interfaceClass,
            InvocationHandler invocationHandler) throws Exception {
    
            String javaCode = buiderJavaFile(interfaceClass);
    //        System.out.println(javaCode);
    
            String className = interfaceClass.getName().substring(interfaceClass.getName().lastIndexOf(".") + 1);
            File file = new File("\com\sun\proxy\$" + className + ".java");
    
            File parentFile = file.getParentFile();
            if (!parentFile.exists()) {
                parentFile.mkdirs();
            }
    
            if (!file.exists()) {
                file.createNewFile();
            }
    
            // 把拼好的Java文件写到硬盘当中
            FileWriter fw = new FileWriter(file);
            fw.write(javaCode);
            fw.close();
    
            // 把写到硬盘的Java文件编译成class
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
            Iterable units = fileMgr.getJavaFileObjects(file);
            JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
            t.call();
            fileMgr.close();
    
    
            // 吧编译上的class文件加载到JVM中
            URL[] urls = new URL[]{new URL("file:G:\\")};
    
    
            URLClassLoader urlClassLoader = new URLClassLoader(urls);
            Class clazz = urlClassLoader.loadClass("com.sun.proxy.$" + className);
    
            Constructor constructor = clazz.getConstructor(InvocationHandler.class);
            return constructor.newInstance(invocationHandler);
        }
    
        /**
         * 生成对应的Java代码
         */
        public static String buiderJavaFile(Class<?> interfaceClass) throws Exception {
    
            String className = interfaceClass.getName().substring(interfaceClass.getName().lastIndexOf(".") + 1);
    
            StringBuilder content = new StringBuilder();
            content.append("package com.sun.proxy;" + ENTER );
            content.append("import java.lang.reflect.Method;" + ENTER);
            content.append("import java.lang.Exception;" + ENTER);
            content.append("import com.michael.pl.InvocationHandler;" + ENTER);
            content.append("public class $" + className + " implements " + interfaceClass.getName() + "{" + ENTER);
    
            content.append(TABLE + "private InvocationHandler i;" + ENTER);
    
            // 添加构造方法
            content.append(forTable(1) + " public $" + className + "(InvocationHandler i){"+ENTER);
            content.append(forTable(1) + "this.i = i;" + ENTER);
            content.append(forTable(1) + "}" + ENTER);
    
    
            Method[] methods = interfaceClass.getMethods();
            for (int i = 0; i < methods.length; i++) {
                Method method = methods[i];
    
                String returnType = method.getReturnType().getName();
    
                int j = 0;
                String paramContent = "";
                String callParam = "";
                String paramClass = "";
                for (Class<?> paramType : method.getParameterTypes()) {
                    paramContent += paramType.getName() + " args" + j + ",";
                    callParam += "args" + j + ",";
                    paramClass += paramType.getName() + ".class,";
                    j++;
                }
                if (paramContent.length()>0) {
                    paramContent = paramContent.substring(0, paramContent.length() - 1);
                    callParam = "new Object[]{" + callParam.substring(0, callParam.length() - 1) + "}";
                    paramClass = paramClass.substring(0, paramClass.length() - 1);
                }
    
                if (callParam.length() == 0) {
                    callParam = "null";
                }
    
    
                String exceptionContent = "";
                for (Class<?> exceptionType : method.getExceptionTypes()) {
                    exceptionContent += exceptionType.getName() + ",";
                }
                if (exceptionContent.length()>0) {
                    exceptionContent = "throws " + exceptionContent.substring(0, exceptionContent.length() - 1);
                }
    
                content.append(forTable(1) + "public " + returnType + " " + method.getName() + "(" + paramContent + ") "
                    + exceptionContent + "  {" + ENTER);
                content.append(forTable(2) + "Method declaredMethod = Class.forName("" + interfaceClass.getName()
                    + "").getDeclaredMethod("" + method.getName() + """ + (paramClass.length() == 0 ? "" :
                    "," + paramClass) + ");" + ENTER);
                if (!"void".equals(method.getReturnType().getName())) {
                    content.append(forTable(2) + "return (" + returnType + ")");
                }
                content.append("i.invock(this,declaredMethod,"+callParam+");" + ENTER);
    
                content.append(forTable(1) + "}" + ENTER);
            }
    
    
            content.append("}" + ENTER);
    
            return content.toString();
    
        }
    
    
        private static String forTable(int i) {
            String str = "";
            for (int j = 0; j < i; j++) {
                str += TABLE;
            }
            return str;
    
        }
    
    
    }
    View Code
    
    
    

    测试类

    package com.michael.pl;
    
    import com.michael.pl.service.LogService;
    import com.michael.pl.service.impl.LogServiceImpl;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class TestDemo {
    
        public static void main(String[] args) throws Exception {
    
    
            // 被代理的对象
            LogServiceImpl logServiceImpl = new LogServiceImpl();
    
            LogService logService = (LogService)MyProxy.newProxyInstance(TestDemo.class.getClassLoader(), LogService.class,
                new InvocationHandler() {
    
                    @Override
                    public Object invock(Object object, Method method, Object[] argss)
                        throws InvocationTargetException, IllegalAccessException {
                        System.out.println(" 代理类容!!");
                        return method.invoke(logServiceImpl, argss);
                    }
    
                });
    
            logService.sayHi();
            logService.out("你好");
    
    
    
        }
    
    }

     代码下载地址:https://files.cnblogs.com/files/MichaelPL/MyProxy.zip



  • 相关阅读:
    swift
    swift
    swift
    swift
    swift
    swift
    swift
    选择排序
    组合 和 继承
    Android中使用LitePal操控SQLite数据库
  • 原文地址:https://www.cnblogs.com/MichaelPL/p/11615756.html
Copyright © 2011-2022 走看看