美文网首页
Spring aop 深入jdk动态代理(自己写动态代理)

Spring aop 深入jdk动态代理(自己写动态代理)

作者: 小2斗鱼 | 来源:发表于2017-08-14 00:32 被阅读0次

    JDK动态代理原理

    实际上jdk的动态代理很简单,最重要的方法就是ProxyGenerator.generateProxyClass(),生成代理类字节码文件,动态编译之后交给类加载器加载也就是调用defineClass0(),然后实例化就完成了。
    http://blog.csdn.net/qq_25235807/article/details/72084759
    这是原来写的一个动态代理的过程。接下来主要是仿照jdk动态代理自己实现一下。

    第一步:自己的代理类MyProxy

    package myproxy;
    
    import java.lang.reflect.Constructor;
    
    public class MyProxy {
    
        private final static Class[] constructorParams = { MyInvocationHandler.class };
        //我们也将构造私有化
        @SuppressWarnings("unused")
        private MyProxy() {
    
        }
    
        protected MyInvocationHandler h;
    
        protected MyProxy(MyInvocationHandler h) {
            this.h = h;
        }
    
        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, MyInvocationHandler h) {
            Object newInstance = null;
            // 获得代理类class对象
            try {
                Class<?> c1 = getProxyClass(loader, interfaces);
                //实例化代理类对象
                Constructor<?> cons = c1.getConstructor(constructorParams);
                newInstance = cons.newInstance(h);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            return newInstance;
    
        }
    
        private static final Class<?> getProxyClass(ClassLoader loader, Class<?>[] interfaces) throws Exception {
            final String proxyName = "$proxy0";
    
            Class<?> interfaceClass = null;
            for (Class<?> intf : interfaces) {
                interfaceClass = Class.forName(intf.getName(), false, loader);
                // 判断被代理的类是否为接口
                if (!interfaceClass.isInterface()) {
                    throw new Exception(intf + "is not an interface");
                }
            }
            //获得生成的代理的字节码文件路径
            String filePath = MyProxyGenerator.generateProxyClass(proxyName, interfaces);
            //通过类加载器加载字节码文件到内存
            MyClassLoader loader0 = new MyClassLoader(filePath);
            //返回一个代理类的Class对象
            Class<?> proxyClass = loader0.findClass(proxyName);
    
            return proxyClass;
        }
    
    }
    

    第二步:拼接源文件,并动态的编译生成字节码文件

    package myproxy;
    
    import java.io.FileWriter;
    import java.io.IOException;
    import java.lang.reflect.Method;
    
    import javax.tools.JavaCompiler;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    
    public class MyProxyGenerator {
        static final String rn="\r\n";
        
        /**
         * @param proxyName
         * @param interfaces
         * @return 生成代理类字节码文件,实际就是动态拼接字节码文件的过程
         */
        public static String  generateProxyClass(String proxyName, Class<?>[] interfaces) {
            StringBuffer simpleIntfName=new StringBuffer();
            StringBuffer intfName=new StringBuffer();
            for(int i=0;i<interfaces.length;i++){
                intfName.append("import ").append(interfaces[i].getName()).append(";"+rn);
                simpleIntfName.append(interfaces[i].getSimpleName());
                if(i!=interfaces.length-1){
                    simpleIntfName.append(",");
                }
            }
            
            String proxyStr="import java.lang.reflect.Method;"
                    +rn
                    +"import myproxy.MyInvocationHandler;"
                    +rn
                    +"import myproxy.MyProxy;"
                    +rn
                    +intfName.toString()
                    +rn
                    +"public final class "+proxyName +" extends MyProxy implements " +
                    simpleIntfName.toString()+" {"
                    +rn
                    +"public "+proxyName+"(MyInvocationHandler h){"
                    +rn
                    +" super(h);"
                    +rn
                    +"}"
                    +rn
                    +createMethods(interfaces)
                    +rn
                    +"}";
            String filePath ="F:/EclipseEEWorkPace/DataStru/src/myproxy/";
            
            try {
                FileWriter writer = new FileWriter(filePath+proxyName+".java");
                writer.write(proxyStr);
                writer.flush();
                writer.close();
            } catch (IOException e) {
                
                e.printStackTrace();
            }
        //拿到编译器 
        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
        //拿到一个文件管理系统
        StandardJavaFileManager fileMgr = javaCompiler.getStandardFileManager(null, null, null);
        //获得java文件
        Iterable unit = fileMgr.getJavaFileObjects(filePath+proxyName+".java");
        //动态编译
         javaCompiler.getTask(null, 
                fileMgr, 
                null, 
                null, 
                null, 
                unit).call();
            return filePath;
        }
    
        private static String createMethods(Class<?>[] interfaces) {
            String methodStr="";
            for(Class<?> intf : interfaces ){
                Method[] methods = intf.getMethods();
                for(Method method : methods){
                    
                    String returnType = method.getReturnType().getSimpleName();
                    StringBuffer isreturn =new StringBuffer();
                    StringBuffer changeReurn =new StringBuffer();
                    if(!returnType.equals("void")){
                        isreturn.append("return ");
                        changeReurn.append("("+returnType+")");
                    }
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    StringBuffer parameterType=new StringBuffer();
                    StringBuffer parameterType1=new StringBuffer();
                    StringBuffer parameterName =new StringBuffer();
                    for(int i=0;i<parameterTypes.length;i++){
                        parameterType1.append(parameterTypes[i].getSimpleName()).append(".class");
                        parameterType.append(parameterTypes[i].getSimpleName())
                        .append(" arg"+i);
                        parameterName.append("arg"+i);
                        if(i!=parameterTypes.length-1){
                            parameterType.append(",");
                            parameterType1.append(",");
                            parameterName.append(",");
                        }
                        
                        
                    }
                     methodStr +="public final " +returnType+" "+ method.getName()+"("+parameterType.toString()+") throws Exception{"
                    +rn
                    +"Method md =" +intf.getSimpleName()+".class.getMethod(\""+method.getName()+"\",new Class[]{"+parameterType1.toString()+"});"
                    +rn
                    +isreturn.toString()+changeReurn.toString()
                    +"this.h.invoke(this, md, new Object[] {"+parameterName.toString()+"});"
                    +rn
                    + "}"
                    +rn;
                }
            }
            return methodStr;
        }
        
        
    }
    

    查看反编译后的class文件

    import java.lang.reflect.Method;
    import myproxy.MyInvocationHandler;
    import myproxy.MyProxy;
    import proxy.DataService;
    import proxy.DataService1;
    
    public final class $proxy0
      extends MyProxy
      implements DataService, DataService1
    {
      public $proxy0(MyInvocationHandler paramMyInvocationHandler)
      {
        super(paramMyInvocationHandler);
      }
      
      public final void update(String paramString)
        throws Exception
      {
        Method localMethod = DataService.class.getMethod("update", new Class[] { String.class });
        this.h.invoke(this, localMethod, new Object[] { paramString });
      }
      
      public final int save(String paramString, int paramInt)
        throws Exception
      {
        Method localMethod = DataService.class.getMethod("save", new Class[] { String.class, Integer.TYPE });
        return ((Integer)this.h.invoke(this, localMethod, new Object[] { paramString, Integer.valueOf(paramInt) })).intValue();
      }
      
      public final String create(String paramString)
        throws Exception
      {
        Method localMethod = DataService1.class.getMethod("create", new Class[] { String.class });
        return (String)this.h.invoke(this, localMethod, new Object[] { paramString });
      }
    }
    
    

    第三步:通过类加载器,将class文件装载到内存

    package myproxy;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class MyClassLoader extends ClassLoader {
        private String proxyClassFilePath;
        FileInputStream fis = null;
        ByteArrayOutputStream baos = null;
    
        public MyClassLoader(String proxyClassFilePath) {
            this.proxyClassFilePath = proxyClassFilePath;
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            byte[] data = loadClassFile(name);
    
            return defineClass(name, data, 0, data.length);
        }
    
        private byte[] loadClassFile(String name) {
            File file = new File(proxyClassFilePath + name + ".class");
            if (file.exists()) {
                try {
                    fis = new FileInputStream(file);
                    baos = new ByteArrayOutputStream();
                    byte[] buf = new byte[1024];
                    int len = 0;
                    while ((len = fis.read(buf)) != -1) {
                        baos.write(buf, 0, len);
                    }
                } catch (FileNotFoundException e) {
    
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            return baos.toByteArray();
        }
    
    }
    
    

    获得代理类实例,验证是否成功

    package proxy;
    
    import java.lang.reflect.Method;
    
    import myproxy.MyInvocationHandler;
    
    public class DataInvocationHandler implements MyInvocationHandler {
        private DataService dataService;
    
        public DataInvocationHandler(DataService dataService) {
            this.dataService = dataService;
        }
    
        private void before() {
            System.out.println("通知类 ,业务方法前调用--before");
    
        }
    
        private void after() {
            System.out.println("通知类 ,业务方法后调用--after");
    
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
            before();
            method.invoke(dataService, args);
            after();
            return null;
    
        }
    
    }
    
    package proxy;
    
    import java.io.IOException;
    
    import myproxy.MyProxy;
    
    public class Main {
    
        public static void main(String[] args) throws IOException {
    
            DataService d = (DataService) MyProxy.newProxyInstance(Main.class.getClassLoader(),
                    new Class<?>[] { DataService.class, DataService1.class },
                    new DataInvocationHandler(new DataServiceImpl()));
            try {
                d.update("name");
            } catch (Exception e) {
                e.printStackTrace();
            }
            /*
             * byte[] bs = ProxyGenerator.generateProxyClass("$proxy1", new
             * Class<?>[]{DataService.class,DataService1.class}); FileOutputStream
             * fs=new FileOutputStream("$proxy1.class"); fs.write(bs); }
             */
    
        }
    }
    
    
    图片.png

    总结

    实际上jdk动态代理非常简单,其核心的方法就是ProxyGenerator.generatorProxyClass()方法生成字节码文件。在它的内部会遍历它实现接口的方法,并且在内部会调用实现InvocationHandler接口的代理的invoke方法实现代理。这也是为什么代理类为什么必须继承InInvocationHandler接口的原因,最后通过defineClass0()将字节码文件装载到内存。
    但是我们自己实现的动态代理要慢很多,可见动态代理实际上还有很多值得研究的地方,其中一点就是缓存!!

    相关文章

      网友评论

          本文标题:Spring aop 深入jdk动态代理(自己写动态代理)

          本文链接:https://www.haomeiwen.com/subject/dvxerxtx.html