代理,自己实现代理

Java实现代理的方式
继承代理
  • 代理对象继承目标对象,
    
聚合代理
  • 在代理对象中传入目标对象,目标对象和代理对象实现同一个接口,代理对象包含目标对象
    
动态代理
  • 实现自己的动态代理,生成动态代理类并且返回代理类对象,这里 目标对象只能实现一个接口
  • 思路
    在这里插入图片描述
package test.utils;

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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ProxyUtil {

    private static final String PACKAGE_NAME = "package";
    private static final String IMPORT = "import";

    private static final String PUBLIC = "public";
    private static final String PRIVATE = "private";
    private static final String CLASS = "class";
    private static final String CLASS_PRE_NAME = "";
    private static final String IMPLEMENTS = "implements";
    private static final String TARGET_NAME = "target";
    private static final String ARG_NAME_PRE = "var";
    private static final String RETURN = "return";
    private static final String JAVA_FILE_SUFFIX_NAME = ".java";
    private static final String OBJECT = "Object";

    private static final String CLASS_STORED_LOCATION = "D:\\apps\\java-develop\\alibaba-repository\\com\\xauv\\";
    //类所在的包位置
    private static final String CLASS_PACKAGE_LOCATION = "com.xauv";
    private static final String NEWLINE = "\n";
    private static final String TAB = "\t";
    private static final String TAB_METHOD_CONTENT = "\t\t";
    private static final String SPILT_SYMBOL = ";";
    private static final String SPACE = " ";
    private static final String COMMA = ",";
    private static final String CALCULATE_SYMBOL = ".";
    private static final String CURLY_BRACES_PRE = "{";
    private static final String CURLY_BRACES_AFTER = "}";
    private static final String PARENTHESES_PRE = "(";
    private static final String PARENTHESES_AFTER = ")";

    public static Object newInstance(String proxyClassName, Object target) {
        Class[] targetInterfaces = target.getClass().getInterfaces();
        Class targetInterface = targetInterfaces[0];

        StringBuilder stringBuilder = new StringBuilder();

        appendPackageInfo(stringBuilder);
        appendImportInfo(stringBuilder, targetInterfaces);
        appendClassHeadInfo(stringBuilder, targetInterfaces, proxyClassName);
        appendConstructorInfo(stringBuilder, proxyClassName, targetInterfaces);
        appendAllDeclaredMethods(stringBuilder, targetInterfaces);

        try {
            File file = new File(CLASS_STORED_LOCATION +
                    CLASS_PRE_NAME + proxyClassName + JAVA_FILE_SUFFIX_NAME);
            if(!file.exists()) {
                file.createNewFile();
            }
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(stringBuilder.toString());
            fileWriter.flush();
            fileWriter.close();

        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

            StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
            Iterable units = fileMgr.getJavaFileObjects(CLASS_STORED_LOCATION + CLASS_PRE_NAME +
                    proxyClassName + JAVA_FILE_SUFFIX_NAME);

            JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
            t.call();
            fileMgr.close();

            URL[] urls = new URL[]{new URL("file:D:\\apps\\java-develop\\alibaba-repository\\")};
            URLClassLoader urlClassLoader = new URLClassLoader(urls);
            Class clazz = urlClassLoader.loadClass(
                    CLASS_PACKAGE_LOCATION + "." + CLASS_PRE_NAME+proxyClassName);
            Constructor constructor = clazz.getConstructor(targetInterface);
            Object proxy = constructor.newInstance(target);

            return proxy;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static void appendPackageInfo(StringBuilder stringBuilder) {
        //包信息
        stringBuilder.append(PACKAGE_NAME)
                .append(SPACE)
                .append(CLASS_PACKAGE_LOCATION)
                .append(SPILT_SYMBOL)
                .append(NEWLINE);
    }

    private static void appendImportInfo(StringBuilder stringBuilder, Class[] interfaces) {
        //引入包信息
        for (int i=0;i<interfaces.length;i++) {
            stringBuilder.append(IMPORT)
                    .append(SPACE)
                    .append(interfaces[i].getName())
                    .append(SPILT_SYMBOL)
                    .append(NEWLINE);
        }
    }

    private static void appendClassHeadInfo(StringBuilder stringBuilder, Class[] interfaces, String proxyClassName) {
        //创建代理类的头信息
        //public class Proxy implements xxx
        stringBuilder.append(PUBLIC)
                .append(SPACE)
                .append(CLASS)
                .append(SPACE);
        String newProxyClassName = CLASS_PRE_NAME + proxyClassName;
        stringBuilder.append(newProxyClassName);
        stringBuilder.append(SPACE);
        stringBuilder.append(IMPLEMENTS);
        stringBuilder.append(SPACE);
        StringBuilder implementsInterfacesContent = new StringBuilder();
        for(int i=0;i<interfaces.length;i++) {
            implementsInterfacesContent.append(interfaces[i].getSimpleName());
            if(i<interfaces.length-1) {
                implementsInterfacesContent.append(COMMA).append(SPACE);
            }
        }
        stringBuilder.append(implementsInterfacesContent);
        stringBuilder.append(CURLY_BRACES_PRE);
        stringBuilder.append(NEWLINE);
    }

    private static void appendConstructorInfo(StringBuilder stringBuilder,
                                              String proxyClassName, Class[] interfaces) {
        //构造方法头信息
        //目标对象信息
        stringBuilder.append(TAB);
        stringBuilder.append(PRIVATE);
        stringBuilder.append(SPACE);

        stringBuilder.append(interfaces[0].getSimpleName());
        stringBuilder.append(SPACE);
        stringBuilder.append(TARGET_NAME);
        stringBuilder.append(SPILT_SYMBOL);
        stringBuilder.append(NEWLINE);
        stringBuilder.append(TAB);
        stringBuilder.append(PUBLIC);
        stringBuilder.append(SPACE);
        stringBuilder.append(proxyClassName);
        stringBuilder.append(PARENTHESES_PRE);
        stringBuilder.append(interfaces[0].getSimpleName()).
                append(SPACE).append(TARGET_NAME);
        stringBuilder.append(PARENTHESES_AFTER);
        stringBuilder.append(SPACE);
        stringBuilder.append(CURLY_BRACES_PRE);
        stringBuilder.append(TAB);
        stringBuilder.append(TAB);
        stringBuilder.append(NEWLINE);
        stringBuilder.append(TAB_METHOD_CONTENT);
        stringBuilder.append("this.").append(TARGET_NAME).append("=")
                .append(TARGET_NAME).append(SPILT_SYMBOL);
        stringBuilder.append(NEWLINE);
        stringBuilder.append(TAB_METHOD_CONTENT);
        stringBuilder.append("System.out.println(\"代理对象初始化\");");
        stringBuilder.append(NEWLINE);
        stringBuilder.append(TAB);
        stringBuilder.append(CURLY_BRACES_AFTER);
        stringBuilder.append(NEWLINE);
    }

    private static void appendAllDeclaredMethods(StringBuilder stringBuilder,
                                              Class[] interfaces) {
        List<Method> methodList = new ArrayList<Method>();
        for(int i=0;i<interfaces.length;i++) {
            Method[] methods = interfaces[i].getDeclaredMethods();
            methodList.addAll(Arrays.asList(methods));
        }
        //接口方法信息
        //Method[] declaredMethods = targetInterface.getDeclaredMethods();
        //for(int methodIndex=0;methodIndex<declaredMethods.length;methodIndex++) {
        for(int methodIndex=0;methodIndex<methodList.size();methodIndex++) {
            //Method method = declaredMethods[methodIndex];
            Method method = methodList.get(methodIndex);
            stringBuilder.append(TAB);
            stringBuilder.append(PUBLIC);
            stringBuilder.append(SPACE);
            stringBuilder.append(method.getReturnType().getSimpleName());
            stringBuilder.append(SPACE);
            stringBuilder.append(method.getName());
            stringBuilder.append(PARENTHESES_PRE);
            //判断方法参数

            Class<?>[] parameterTypes = method.getParameterTypes();
            int index = 0;
            StringBuilder argsSb = new StringBuilder();
            for (int i = 0; i <parameterTypes.length ; i++) {
                stringBuilder.append(parameterTypes[i].getSimpleName());
                stringBuilder.append(SPACE);
                stringBuilder.append(ARG_NAME_PRE).append(index);
                argsSb.append(ARG_NAME_PRE).append(index);
                index++;
                if(i < parameterTypes.length-1) {
                    stringBuilder.append(COMMA);
                    stringBuilder.append(SPACE);
                    argsSb.append(COMMA).append(SPACE);
                }
            }
            stringBuilder.append(PARENTHESES_AFTER);
            stringBuilder.append(SPACE);
            stringBuilder.append(CURLY_BRACES_PRE);
            stringBuilder.append(NEWLINE);

            stringBuilder.append(TAB);
            stringBuilder.append(TAB);
            stringBuilder.append("System.out.println(\"代理类中 -- 目标对象逻辑\");");
            stringBuilder.append(NEWLINE);

            if(!method.getReturnType().getSimpleName().equals("void")) {
                stringBuilder.append(TAB_METHOD_CONTENT);

                stringBuilder.append(RETURN);
                stringBuilder.append(SPACE);
                stringBuilder.append(TARGET_NAME).append(CALCULATE_SYMBOL).append(method.getName())
                        .append(PARENTHESES_PRE).append(argsSb).append(PARENTHESES_AFTER).append(SPILT_SYMBOL);
                stringBuilder.append(NEWLINE);
                stringBuilder.append(NEWLINE);
            }

            stringBuilder.append(TAB);
            stringBuilder.append(CURLY_BRACES_AFTER);

            stringBuilder.append(NEWLINE);
            if(methodIndex < methodList.size() - 1) {
                continue;
            }
            stringBuilder.append(CURLY_BRACES_AFTER);
        }
    }
}


  • 用法:
    在这里插入图片描述

JDK动态代理

  • 通过反射得到字节码
  • 把字节码转换成Class,这个转换方法事 native 方法,在openjdk中实现,使用 C/C++ 实现

CGLIB

  • 基于 ASM 字节码框架

性能对比(使用主要看场景)

  • 底层都是操作字节码,速度相差不大,

Javassist(字节码编程)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值