模仿CGLib,通过使用字节码实现动态代理

   实现思路:在内存中通过拼接字符串的方式继承被代理的类,生成的代理类字符串通过JavaCompiler编译为字节码,并将字节码保存在内存中,最后通过自定义的类加载器加载到元数据区生成了代理类的Class对象。

   Enhancer类:

package com.lj.proxy;

import lombok.Data;

import javax.tools.*;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.nio.CharBuffer;
import java.util.*;

/**
 * @Description 模仿CGlib获取代理类,在内存中通过继承的方式动态生成代理类,再在内存中完成编译,最后返回代理对象
 * @Date 2020/8/22 15:30
 * @Created by 长白山西红柿
 */
@Data
public class Enhancer {
    /**
     * 生成的代理类,key为类名,value为字节码
     */
    private static Map<String, byte[]> proxyClassMap = new HashMap<>();
    /**
     * 被代理类名
     */
    private Class superclass;
    /**
     * 被代理类的对象
     */
    private Object superObject;
    /**
     * 代理类执行的方法,(目前只支持around)
     */
    private MethodInterceptor methodInterceptor;

    private static String path = "com.lj.proxy.proxyClass.";
    /**
     * 代理类的类加载器
     */
    private static ProxyClassLoader proxyClassLoader = new ProxyClassLoader();

    /**
     * 要求被代理的类必须有无参构造方法
     * @return
     */
    public Object create() {
        if (Objects.isNull(superclass) || Objects.isNull(methodInterceptor)) {
            return null;
        }

        if (Objects.nonNull(superObject) && !superclass.equals(superObject.getClass())) {
            return null;
        }

        String className = superclass.getSimpleName() + "Proxy$" + proxyClassMap.size();
        // 编译成字节码文件
        compile(className, createProxyClass(className));

        Object result = null;
        try {
            // 将字节码通过自定义类加载器加载到元数据区
            Class<?> proxyClass = proxyClassLoader.loadClass(path + className);

            // 生成代理对象并填充数据
            result = proxyClass.newInstance();
            superObject = superObject == null ? superclass.newInstance() : superObject ;
            Field superObjectField = proxyClass.getDeclaredField("superObject");
            superObjectField.setAccessible(true);
            superObjectField.set(result, superObject);

            Field methodInterceptorField = proxyClass.getDeclaredField("methodInterceptor");
            methodInterceptorField.setAccessible(true);
            methodInterceptorField.set(result, methodInterceptor);

            HashMap<String, Method> methodMap = new HashMap<>();
            for (Method method : superclass.getMethods()) {
                methodMap.put(method.getName(), method);
            }
            Field methodMapField = proxyClass.getDeclaredField("methodMap");
            methodMapField.setAccessible(true);
            methodMapField.set(result, methodMap);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }


        return result;
    }

    /**
     * 本方法生成的字符串可以见最后的实例
     * @return 返回字符串形式的代理类java文件
     */
    private String createProxyClass(String className) {
        StringBuilder sourceCode = new StringBuilder();
        // 获取系统换行符
//        String lineFeed =  System.getProperty("line.separator");

        sourceCode.append("package com.lj.proxy.proxyClass;\n");
        sourceCode.append("import ").append(superclass.getName()).append(";\n");
        sourceCode.append("import com.lj.proxy.MethodInterceptor;\n" +
                "import java.lang.reflect.Method;\n" +
                "import java.util.HashMap;\n" +
                "import java.util.Map;\n");

        // 代理类类开始的地方
        sourceCode.append("public class ").append(className).append(" extends ").append(superclass.getSimpleName()).append(" {\n");
        // 代理类的成员
        sourceCode.append("private MethodInterceptor methodInterceptor;\n" +
                "private Object superObject;\n" +
                "private Map<String, Method> methodMap;\n");
        // 代理对象真正执行的方法,¥是为了避免重名
        sourceCode.append("private <T> T doAround¥(String methodName, Object[] args) {\n" +
                "return (T) methodInterceptor.intercept(superObject, methodMap.get(methodName), args);\n" +
                "}\n");

        // 代理类的所有公有方法
        Method[] methods = superclass.getMethods();
        for (Method method : methods) {
            // 不能代理static和final方法
            if (Modifier.isStatic(method.getModifiers()) || Modifier.isFinal(method.getModifiers())) {
                continue;
            }

            sourceCode.append("@Override\n");
            sourceCode.append("public ").append(method.getReturnType().getName()).append(" ").append(method.getName()).append(" (");

            Class<?>[] args = method.getParameterTypes();
            if (args.length <= 0) {
                sourceCode.append(") {\n");
                // 判断方法是否有返回值
                if (!method.getReturnType().getName().equals("void")) {
                    sourceCode.append("return ");
                }

                sourceCode.append("doAround¥(\"").append(method.getName()).append("\", null);\n");
            } else {
                // 先构造入参
                for (int i = 0; i < args.length; i++) {
                    if (i != 0) {
                        sourceCode.append(", ");
                    }
                    sourceCode.append(args[i].getName()).append(" var").append(i);
                }
                sourceCode.append(") {\n");

                sourceCode.append("Object[] args = new Object[methodMap.get(\"").append(method.getName()).append("\").getParameterTypes().length];\n");
                // 将所有参数填入Object[] args
                for (int i = 0; i < args.length; i++) {
                    sourceCode.append("args[").append(i).append("] = ").append(" var").append(i).append(";\n");
                }
                // 判断方法是否有返回值
                if (!method.getReturnType().getName().equals("void")) {
                    sourceCode.append("return ");
                }

                sourceCode.append("doAround¥(\"").append(method.getName()).append("\", args);\n");
            }


            // 一个代理方法构造结束
             sourceCode.append("}\n");
        }

        // 代理类构造结束
        sourceCode.append("}");
        return sourceCode.toString();
    }

    /**
     * 将字符串形式的代理类java文件编译成字节码,并放在proxyClassMap里
     * @param className 生成的代理类名
     * @param sourceCode 字符串形式的代理类java文件
     */
    private void compile(String className, String sourceCode) {
        //获取系统Java编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        //获取Java文件管理器
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        // 设置编译后的字节码直接放在内存里,需要重写JavaFileManager的openOutputStream方法
        JavaFileManager jfm = new ForwardingJavaFileManager(fileManager) {
            public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location,
                                                       String className,
                                                       JavaFileObject.Kind kind,
                                                       FileObject sibling) throws IOException {
                if(kind == JavaFileObject.Kind.CLASS) {
                    return new SimpleJavaFileObject(URI.create(className + ".class"), JavaFileObject.Kind.CLASS) {
                        public OutputStream openOutputStream() {
                            return new FilterOutputStream(new ByteArrayOutputStream()) {
                                public void close() throws IOException{
                                    out.close();
                                    ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
                                    proxyClassMap.put(className, bos.toByteArray());
                                }
                            };
                        }
                    };
                }else{
                    return super.getJavaFileForOutput(location, className, kind, sibling);
                }
            }
        };

        // 设置获取源码的方式为字符串,需要重写JavaFileObject的getCharContent方法
        Iterable<? extends JavaFileObject> compilationUnits = new Iterable<SimpleJavaFileObject>() {
            @Override
            public Iterator<SimpleJavaFileObject> iterator() {
                SimpleJavaFileObject sourceJavaFileObject = new SimpleJavaFileObject(URI.create(className + ".java"),
                        JavaFileObject.Kind.SOURCE){
                    public CharBuffer getCharContent(boolean b) {
                        return CharBuffer.wrap(sourceCode);
                    }
                };
                List<SimpleJavaFileObject> list = new ArrayList<>();
                list.add(sourceJavaFileObject);
                return list.iterator();
            }
        };

        //生成编译任务
        JavaCompiler.CompilationTask task = compiler.getTask(null, jfm, null, null, null, compilationUnits);
        //执行编译任务
        task.call();
    }

     private static class ProxyClassLoader extends ClassLoader {
        public ProxyClassLoader(){
        }

        /**
         * 重写findClass方法
         * @param name 是我们这个类的全路径
         * @return
         * @throws ClassNotFoundException
         */
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            Class log = null;
            // 获取该class文件字节码数组
            byte[] classData = getData(name);

            if (classData != null) {
                // 将class的字节码数组转换成Class类的实例
                log = defineClass(name, classData, 0, classData.length);
            }
            return log;
        }

        /**
         * 将class文件转化为字节码数组
         *          * @return
         */
        private byte[] getData(String name) {
            return proxyClassMap.get(name);
        }
    }
}
/** 被代理类com.lj.model.Student生成的代理类(示例)
  package com.lj.proxy.proxyClass;
  import com.lj.model.Student;
  import com.lj.proxy.MethodInterceptor;
  import java.lang.reflect.Method;
  import java.util.HashMap;
  import java.util.Map;
  public class StudentProxy$0 extends Student {
      private MethodInterceptor methodInterceptor;
      private Object superObject;
      private Map<String, Method> methodMap;
      private <T> T doAround¥(String methodName, Object[] args) {
         return (T) methodInterceptor.intercept(superObject, methodMap.get(methodName), args);
      }
      @Override
      public boolean equals (java.lang.Object var0) {
          Object[] args = new Object[methodMap.get("equals").getParameterTypes().length];
          args[0] =  var0;
          return doAround¥("equals", args);
      }
      @Override
      public java.lang.String toString () {
          return doAround¥("toString", null);
      }
      @Override
      public int hashCode () {
          return doAround¥("hashCode", null);
      }
      @Override
      public java.lang.String getName () {
          return doAround¥("getName", null);
      }
      @Override
      public java.lang.String getId () {
          return doAround¥("getId", null);
      }
      @Override
      public void setName (java.lang.String var0) {
          Object[] args = new Object[methodMap.get("setName").getParameterTypes().length];
          args[0] =  var0;
          doAround¥("setName", args);
      }
      @Override
      public void setId (java.lang.String var0) {
          Object[] args = new Object[methodMap.get("setId").getParameterTypes().length];
          args[0] =  var0;
          doAround¥("setId", args);
      }
  }
 */

被代理的model类:

package com.lj.model;

import lombok.Data;

/**
 * @Description TODO
 * @Date 2020/8/22 15:27
 * @Created by 长白山西红柿
 */
@Data
public class Student {
    private String id;
    private String name;

    public void setId(String s) {
        this.id = s;
    }
}

测试Demo:

import com.lj.model.Student;
import com.lj.proxy.Enhancer;
import com.lj.proxy.MethodInterceptor;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Description 简单模仿CGLib通过在内存中生成被代理类的子类实现动态代理(没有做代理链)
 * @Date 2020/8/22 15:26
 * @Created by 长白山西红柿
 */
public class Demo {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        // 必须设置超类和拦截器方法
        enhancer.setSuperclass(Student.class);
        enhancer.setMethodInterceptor((Object o, Method method, Object[] objects) -> {
                Object result = null;
                System.out.println("对方法" + method.getName() + "前置拦截");
                try {
                    result = method.invoke(o, objects);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
                System.out.println("对方法" + method.getName() + "后置拦截");
                return result;
        });
        Student student = (Student) enhancer.create();
        // 如果正确会输出前置和后置拦截
        student.setId("007");
        System.out.println(student.getId());
//        try {
//            System.out.println(Student.class.getMethod("getClass", String.class));
//        } catch (NoSuchMethodException e) {
//            e.printStackTrace();
//        }
    }
}

测试结果:

对方法setId前置拦截
对方法setId后置拦截
对方法getId前置拦截
对方法getId后置拦截
007
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值