java动态代理-jdk动态代理原理解析

场景

动态代理是一个比较常见的场景,广泛用于方法增强、AOP(面向切面编程)、测试、监控等场景。市面上常用的动态代理主要是 jdk动态代理和cglib动态代理,javaassist 和 byteBuddy同样可以做动态代理。一般使用jdk动态代理代理方法 适合于代理接口,它不需要引入额外依赖,一般cglib适合于代理没有实现接口的类,性能较好。Javaassist就更加高级了,可以自由生成类字节码,可以自由改变类的行为,Byte Buddy主要是比较灵活,和 javaassist 差不多。我们之前使用Byte Buddy 做了自动生成接口的操作。

jdk动态代理的原理

demo

java 复制代码
interface MyInterface {
    void performAction();
}

class MyInterfaceImpl implements MyInterface {
    public void performAction() {
        System.out.println("Action performed");
    }
}

class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method call");
        Object result = method.invoke(target, args);
        System.out.println("After method call");
        return result;
    }
}

public class JdkProxyDemo {
    public static void main(String[] args) {
        MyInterfaceImpl realObject = new MyInterfaceImpl();
        MyInterface proxyInstance = (MyInterface) Proxy.newProxyInstance(
                MyInterfaceImpl.class.getClassLoader(),
                new Class[]{MyInterface.class},
                new MyInvocationHandler(realObject)
        );
        proxyInstance.performAction();
    }
}

jdk动态代理使用起来很简单,一个接口,n实现类 ,一个handler足够了,他的原理比较简单

java 复制代码
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h) {
        Objects.requireNonNull(h);

        @SuppressWarnings("removal")
        final Class<?> caller = System.getSecurityManager() == null
                                    ? null
                                    : Reflection.getCallerClass();

        /*
         * Look up or generate the designated proxy class and its constructor.
         */
        Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);

        return newProxyInstance(caller, cons, h);
    }

首先是检查handler和验证安全性,然后getProxyConstructor获取代理类的构造函数。

java 复制代码
 private static Constructor<?> getProxyConstructor(Class<?> caller,
                                                      ClassLoader loader,
                                                      Class<?>... interfaces)
    {
        // optimization for single interface
        if (interfaces.length == 1) {
            Class<?> intf = interfaces[0];
            if (caller != null) {
                checkProxyAccess(caller, loader, intf);
            }
            return proxyCache.sub(intf).computeIfAbsent(
                loader,
                (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
            );
        } else {
            // interfaces cloned
            final Class<?>[] intfsArray = interfaces.clone();
            if (caller != null) {
                checkProxyAccess(caller, loader, intfsArray);
            }
            final List<Class<?>> intfs = Arrays.asList(intfsArray);
            return proxyCache.sub(intfs).computeIfAbsent(
                loader,
                (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
            );
        }
    }

这个过程也很简单,首先是 单个接口

当只有一个接口时,代码直接使用这个接口(Class<?> intf = interfaces0;)。

在这种情况下,代理类只需要实现这一个接口,所以处理起来更直接、更简单。

代理缓存(proxyCache)的子映射使用这个单一的接口作为键。首先验证完该类是否可以被代理之后,先去缓存拿取,拿不到则构建

java 复制代码
    (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()

代理构造器

java 复制代码
        ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) {
            if (!VM.isModuleSystemInited()) {
                throw new InternalError("Proxy is not supported until "
                        + "module system is fully initialized");
            }
            if (interfaces.size() > 65535) {
                throw new IllegalArgumentException("interface limit exceeded: "
                        + interfaces.size());
            }

            Set<Class<?>> refTypes = referencedTypes(loader, interfaces);

            // IAE if violates any restrictions specified in newProxyInstance
            validateProxyInterfaces(loader, interfaces, refTypes);

            this.interfaces = interfaces;
            this.module = mapToModule(loader, interfaces, refTypes);
            assert getLoader(module) == loader;
        }

首先检查模块是否已经完全初始化,这是j9引入的新特性,模块的概念,模块系统的初始化是启动过程的一个关键部分。它负责设置模块路径,确定哪些模块是可访问的,以及它们如何相互作用。

如果模块系统没有完全初始化,许多基于模块的操作,比如动态代理的创建,都不能正常进行。这是因为代理类可能需要跨越不同模块的边界,访问它们的类或接口。

其次检查接口数量是否大于65535,是否超出限制。

再来就是收集引用类型

java 复制代码
      /*
         * Returns all types referenced by all public non-static method signatures of
         * the proxy interfaces
         */
        private static Set<Class<?>> referencedTypes(ClassLoader loader,
                                                     List<Class<?>> interfaces) {
            var types = new HashSet<Class<?>>();
            for (var intf : interfaces) {
                for (Method m : intf.getMethods()) {
                    if (!Modifier.isStatic(m.getModifiers())) {
                        addElementType(types, m.getReturnType());
                        addElementTypes(types, m.getSharedParameterTypes());
                        addElementTypes(types, m.getSharedExceptionTypes());
                    }
                }
            }
            return types;
        }

其实就是收集接口中有哪些方法,方法中有哪些参数,返回值是什么,异常信息是什么这些云云。这个方法的目的是为动态代理类的创建准备必要的类型信息

再来就是验证代理接口:

java 复制代码
validateProxyInterfaces(loader, interfaces, refTypes);

非常简单

java 复制代码
    private static void validateProxyInterfaces(ClassLoader loader,
                                                    List<Class<?>> interfaces,
                                                    Set<Class<?>> refTypes)
        {
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.size());
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!intf.isInterface()) {
                    throw new IllegalArgumentException(intf.getName() + " is not an interface");
                }

                if (intf.isHidden()) {
                    throw new IllegalArgumentException(intf.getName() + " is a hidden interface");
                }

                if (intf.isSealed()) {
                    throw new IllegalArgumentException(intf.getName() + " is a sealed interface");
                }

                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                ensureVisible(loader, intf);

                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(intf, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException("repeated interface: " + intf.getName());
                }
            }

            for (Class<?> type : refTypes) {
                ensureVisible(loader, type);
            }
        }

验证是不是一个接口,是不是隐藏和密封(15新特性)的接口,在15,引入了隐藏和密封的概念,随后验证接口和之前获取的类型能不能被获取加载。

再来就是完善构建器

java 复制代码
            this.interfaces = interfaces;
            this.module = mapToModule(loader, interfaces, refTypes);
            assert getLoader(module) == loader;

再来就是构建 构造方法了

java 复制代码
   Constructor<?> build() {
            Class<?> proxyClass = defineProxyClass(module, interfaces);
            assert !module.isNamed() || module.isOpen(proxyClass.getPackageName(), Proxy.class.getModule());

            final Constructor<?> cons;
            try {
                cons = proxyClass.getConstructor(constructorParams);
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
            return cons;
        }
java 复制代码
  private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) {
            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
            boolean nonExported = false;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;  // non-public, final
                    String pkg = intf.getPackageName();
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                                "non-public interfaces from different packages");
                    }
                } else {
                    if (!intf.getModule().isExported(intf.getPackageName())) {
                        // module-private types
                        nonExported = true;
                    }
                }
            }

            if (proxyPkg == null) {
                // all proxy interfaces are public and exported
                if (!m.isNamed())
                    throw new InternalError("ununamed module: " + m);
                proxyPkg = nonExported ? PROXY_PACKAGE_PREFIX + "." + m.getName()
                                       : m.getName();
            } else if (proxyPkg.isEmpty() && m.isNamed()) {
                throw new IllegalArgumentException(
                        "Unnamed package cannot be added to " + m);
            }

            if (m.isNamed()) {
                if (!m.getDescriptor().packages().contains(proxyPkg)) {
                    throw new InternalError(proxyPkg + " not exist in " + m.getName());
                }
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg.isEmpty()
                                    ? proxyClassNamePrefix + num
                                    : proxyPkg + "." + proxyClassNamePrefix + num;

            ClassLoader loader = getLoader(m);
            trace(proxyName, m, loader, interfaces);

            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);
            try {
                Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
                                              null, "__dynamic_proxy__");
                reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
                return pc;
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }

这个方法意思就是创建一个代理类,方法比较长,但是无难度。

java 复制代码
 String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
            boolean nonExported = false;

首先定义包名访问符和接口是否有接口未被模块导出等变量 一个初始化的操作啊。

java 复制代码
   for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;  // non-public, final
                    String pkg = intf.getPackageName();
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                                "non-public interfaces from different packages");
                    }
                } else {
                    if (!intf.getModule().isExported(intf.getPackageName())) {
                        // module-private types
                        nonExported = true;
                    }
                }
            }
             if (proxyPkg == null) {
                // all proxy interfaces are public and exported
                if (!m.isNamed())
                    throw new InternalError("ununamed module: " + m);
                proxyPkg = nonExported ? PROXY_PACKAGE_PREFIX + "." + m.getName()
                                       : m.getName();
            } else if (proxyPkg.isEmpty() && m.isNamed()) {
                throw new IllegalArgumentException(
                        "Unnamed package cannot be added to " + m);
            }

            if (m.isNamed()) {
                if (!m.getDescriptor().packages().contains(proxyPkg)) {
                    throw new InternalError(proxyPkg + " not exist in " + m.getName());
                }
            }

他把接口给遍历了啊,注意这里是有单一包名限制的。

遍历传入的接口列表interfaces。对于每个接口intf:

不是公共的,设置为FINAL,获取包名,如果接口的包名与proxyPkg不同,则抛出异常。

else:如果接口是公共的:

if (!intf.getModule().isExported(intf.getPackageName())):如果接口所在的模块没有导出该接口的包,则将nonExported设置为true。

上面的代码主打一个验证,就是杂七杂八的验证。

给代理类起名字

java 复制代码
 /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg.isEmpty()
                                    ? proxyClassNamePrefix + num
                                    : proxyPkg + "." + proxyClassNamePrefix + num;

获取类加载器并记录跟踪信息,随后生成代理类的字节码并定义类,然后定义代理

java 复制代码
            ClassLoader loader = getLoader(m);
            trace(proxyName, m, loader, interfaces);

            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);
            try {
                Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
                                              null, "__dynamic_proxy__");
                reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
                return pc;
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }

重要代码

java 复制代码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);:使用ProxyGenerator生成代理类的字节码。
java 复制代码
static byte[] generateProxyClass(ClassLoader loader,
                                     final String name,
                                     List<Class<?>> interfaces,
                                     int accessFlags) {
        ProxyGenerator gen = new ProxyGenerator(loader, name, interfaces, accessFlags);
        final byte[] classFile = gen.generateClassFile();

        if (saveGeneratedFiles) {
            java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<Void>() {
                        public Void run() {
                            try {
                                int i = name.lastIndexOf('.');
                                Path path;
                                if (i > 0) {
                                    Path dir = Path.of(dotToSlash(name.substring(0, i)));
                                    Files.createDirectories(dir);
                                    path = dir.resolve(name.substring(i + 1) + ".class");
                                } else {
                                    path = Path.of(name + ".class");
                                }
                                Files.write(path, classFile);
                                return null;
                            } catch (IOException e) {
                                throw new InternalError(
                                        "I/O exception saving generated file: " + e);
                            }
                        }
                    });
        }

        return classFile;
    }

ProxyGenerator gen = new ProxyGenerator(loader, name, interfaces, accessFlags); 创建代理生成器,生成字节码:

java 复制代码
final byte[] classFile = gen.generateClassFile();:通过调用ProxyGenerator对象的generateClassFile方法,生成代理类的字节码,并将其存储在字节数组classFile中。

给字节码中注入方法,先注入基本方法 什么 hashCode 什么 equals 什么 toString ,然后再把接口方法注入进去,然后检查返回参数,随后生成构造方法,其实我们的关注点应该在generateMethod 方法上,这才是灵魂。

java 复制代码
  private byte[] generateClassFile() {
        visit(V14, accessFlags, dotToSlash(className), null,
                JLR_PROXY, typeNames(interfaces));

        /*
         * Add proxy methods for the hashCode, equals,
         * and toString methods of java.lang.Object.  This is done before
         * the methods from the proxy interfaces so that the methods from
         * java.lang.Object take precedence over duplicate methods in the
         * proxy interfaces.
         */
        addProxyMethod(hashCodeMethod);
        addProxyMethod(equalsMethod);
        addProxyMethod(toStringMethod);

        /*
         * Accumulate all of the methods from the proxy interfaces.
         */
        for (Class<?> intf : interfaces) {
            for (Method m : intf.getMethods()) {
                if (!Modifier.isStatic(m.getModifiers())) {
                    addProxyMethod(m, intf);
                }
            }
        }

        /*
         * For each set of proxy methods with the same signature,
         * verify that the methods' return types are compatible.
         */
        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
            checkReturnTypes(sigmethods);
        }

        generateConstructor();

        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
            for (ProxyMethod pm : sigmethods) {
                // add static field for the Method object
                visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, pm.methodFieldName,
                        LJLR_METHOD, null, null);

                // Generate code for proxy method
                pm.generateMethod(this, className);
            }
        }

        generateStaticInitializer();
        generateLookupAccessor();
        return toByteArray();
    }
java 复制代码
  private void addProxyMethod(ProxyMethod pm) {
        String sig = pm.shortSignature;
        List<ProxyMethod> sigmethods = proxyMethods.computeIfAbsent(sig,
                (f) -> new ArrayList<>(3));
        sigmethods.add(pm);
    }

灵魂方法: 这个方法它实现了将方法调用转发到InvocationHandler的逻辑。

java 复制代码
      private void generateMethod(ClassWriter cw, String className) {
            MethodType mt = MethodType.methodType(returnType, parameterTypes);
            String desc = mt.toMethodDescriptorString();
            int accessFlags = ACC_PUBLIC | ACC_FINAL;
            if (method.isVarArgs()) accessFlags |= ACC_VARARGS;

            MethodVisitor mv = cw.visitMethod(accessFlags,
                    method.getName(), desc, null,
                    typeNames(Arrays.asList(exceptionTypes)));

            int[] parameterSlot = new int[parameterTypes.length];
            int nextSlot = 1;
            for (int i = 0; i < parameterSlot.length; i++) {
                parameterSlot[i] = nextSlot;
                nextSlot += getWordsPerType(parameterTypes[i]);
            }

            mv.visitCode();
            Label L_startBlock = new Label();
            Label L_endBlock = new Label();
            Label L_RuntimeHandler = new Label();
            Label L_ThrowableHandler = new Label();

            List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes);
            if (catchList.size() > 0) {
                for (Class<?> ex : catchList) {
                    mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_RuntimeHandler,
                            dotToSlash(ex.getName()));
                }

                mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_ThrowableHandler,
                        JL_THROWABLE);
            }
            mv.visitLabel(L_startBlock);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, JLR_PROXY, handlerFieldName,
                    LJLR_INVOCATION_HANDLER);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETSTATIC, dotToSlash(className), methodFieldName,
                    LJLR_METHOD);

            if (parameterTypes.length > 0) {
                // Create an array and fill with the parameters converting primitives to wrappers
                emitIconstInsn(mv, parameterTypes.length);
                mv.visitTypeInsn(Opcodes.ANEWARRAY, JL_OBJECT);
                for (int i = 0; i < parameterTypes.length; i++) {
                    mv.visitInsn(DUP);
                    emitIconstInsn(mv, i);
                    codeWrapArgument(mv, parameterTypes[i], parameterSlot[i]);
                    mv.visitInsn(Opcodes.AASTORE);
                }
            } else {
                mv.visitInsn(Opcodes.ACONST_NULL);
            }

            mv.visitMethodInsn(INVOKEINTERFACE, JLR_INVOCATION_HANDLER,
                    "invoke",
                    "(Ljava/lang/Object;Ljava/lang/reflect/Method;" +
                            "[Ljava/lang/Object;)Ljava/lang/Object;", true);

            if (returnType == void.class) {
                mv.visitInsn(POP);
                mv.visitInsn(RETURN);
            } else {
                codeUnwrapReturnValue(mv, returnType);
            }

            mv.visitLabel(L_endBlock);

            // Generate exception handler
            mv.visitLabel(L_RuntimeHandler);
            mv.visitInsn(ATHROW);   // just rethrow the exception

            mv.visitLabel(L_ThrowableHandler);
            mv.visitVarInsn(ASTORE, 1);
            mv.visitTypeInsn(Opcodes.NEW, JLR_UNDECLARED_THROWABLE_EX);
            mv.visitInsn(DUP);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKESPECIAL, JLR_UNDECLARED_THROWABLE_EX,
                    "<init>", "(Ljava/lang/Throwable;)V", false);
            mv.visitInsn(ATHROW);
            // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
            mv.visitMaxs(-1, -1);
            mv.visitEnd();
        }

核心是 生成代理方法的主体:

加载this和InvocationHandler引用,以及被调用的方法对象。

创建参数对象数组,并将方法参数转换为对象,存储在数组中。

使用InvocationHandler的invoke方法来实现方法的动态代理调用。

加载this和InvocationHandler引用,以及被调用的方法对象:

mv.visitVarInsn(ALOAD, 0);:加载this引用到栈顶。在Java字节码中,ALOAD用于加载一个对象引用到栈顶,而这里的0表示加载位于局部变量表中索引为0的对象,即this引用。

mv.visitFieldInsn(GETFIELD, JLR_PROXY, handlerFieldName, LJLR_INVOCATION_HANDLER);:获取当前代理实例的InvocationHandler字段,将其压入操作数栈。这里GETFIELD是用于访问对象的字段。

mv.visitVarInsn(ALOAD, 0);:再次加载this引用到栈顶。

mv.visitFieldInsn(GETSTATIC, dotToSlash(className), methodFieldName, LJLR_METHOD);:获取静态字段,即当前正在执行的Method对象的引用。

我们回来

java 复制代码
     Constructor<?> build() {
            Class<?> proxyClass = defineProxyClass(module, interfaces);
            assert !module.isNamed() || module.isOpen(proxyClass.getPackageName(), Proxy.class.getModule());

            final Constructor<?> cons;
            try {
                cons = proxyClass.getConstructor(constructorParams);
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
            return cons;
        }

类都生成了 拿到构造简直是小菜一碟了,后面自然是绕过安全检查,设置构造可见。

java 复制代码
    private static Object newProxyInstance(Class<?> caller, // null if no SecurityManager
                                           Constructor<?> cons,
                                           InvocationHandler h) {
        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (caller != null) {
                checkNewProxyPermission(caller, cons.getDeclaringClass());
            }

            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException | InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        }

然后就示例化了,最复杂的是生成代理类那一块。

生成后代理类伪代码应该是

java 复制代码
import java.lang.reflect.*;

public class DynamicProxyClass implements HelloInterface {
    private InvocationHandler handler;

    public DynamicProxyClass(InvocationHandler handler) {
        this.handler = handler;
    }

    @Override
    public void performAction() {
        try {
            Method method = HelloInterface.class.getMethod("performAction");
            this.handler.invoke(this, method, null);
        } catch (Throwable throwable) {
            // 处理异常
        }
    }
    @Override
    public String toString() {
        try {
            Method method = Object.class.getMethod("toString");
            return (String) handler.invoke(this, method, null);
        } catch (Throwable throwable) {
            // 处理异常
            return null;
        }
    }

    @Override
    public boolean equals(Object obj) {
        try {
            Method method = Object.class.getMethod("equals", Object.class);
            return (Boolean) handler.invoke(this, method, new Object[]{obj});
        } catch (Throwable throwable) {
            // 处理异常
            return false;
        }
    }

    @Override
    public int hashCode() {
        try {
            Method method = Object.class.getMethod("hashCode");
            return (Integer) handler.invoke(this, method, null);
        } catch (Throwable throwable) {
            // 处理异常
            return 0;
        }
    }
}

差不多就这样。

总结

差不多就是 先 接口定义->实现InvocationHandler -> 安全性检查 -> 生成代理类字节码 -> 实例化代理类 不复杂。 比起 javaaasit和bybtBuddy 还是很简单,弟中弟了 属于是。

相关推荐
Scott9999HH8 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔8 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社9 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海9 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖10 小时前
JDK 26 新特性详解
java·开发语言
马优晨11 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区13 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大13 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai13 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说13 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json