You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否通过JSON文件在运行时动态创建Java类?

动态生成指定类与方法的实现方案

需求回顾

给定如下JSON定义:

{
  "Invoice_iDoc": {
    "name": "Invoice",
    "methods": [
      "customer",
      "project",
      "cost"
    ]
  },
  "PO": {
    "name": "PO",
    "methods": [
      "date",
      "amount"
    ]
  }
}

需要动态创建Invoice(包含customer(String)、project(String)、cost(String)方法)和PO(包含date(String)、amount(String)方法)类,且无需提前存在类文件。


问题解答

1. 能否创建带有指定方法的类?

可以实现。无需提前编写类文件,通过字节码生成技术或动态代理就能构建出包含指定方法的类。

2. 能否在运行时生成这些类?

完全可行,Java提供了多种运行时生成类的方式,以下是两种常用方案:


方案一:动态代理(基于接口)

如果可以接受基于接口的实现,动态代理是轻量的选择:

  1. 定义通用接口适配方法调用
  2. 通过Proxy.newProxyInstance生成代理类,在InvocationHandler中处理方法逻辑

示例代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class DynamicProxyDemo {
    public static void main(String[] args) throws Exception {
        // 生成Invoice代理实例
        Object invoice = createDynamicProxy(new String[]{"customer", "project", "cost"});
        // 调用方法
        invoice.getClass().getMethod("customer", String.class).invoke(invoice, "C001");
        
        // 生成PO代理实例
        Object po = createDynamicProxy(new String[]{"date", "amount"});
        po.getClass().getMethod("date", String.class).invoke(po, "2024-05-20");
    }

    private static Object createDynamicProxy(String[] methodNames) {
        return Proxy.newProxyInstance(
                DynamicProxyDemo.class.getClassLoader(),
                new Class<?>[]{DynamicBusiness.class},
                (proxy, method, args) -> {
                    if (Arrays.asList(methodNames).contains(method.getName())) {
                        System.out.printf("调用%s方法,参数:%s%n", method.getName(), args[0]);
                    }
                    return null;
                }
        );
    }

    // 通用业务接口
    public interface DynamicBusiness {
        void customer(String param);
        void project(String param);
        void cost(String param);
        void date(String param);
        void amount(String param);
    }
}

方案二:字节码操作库(生成独立类)

如果需要生成独立的类(而非代理),可以用ByteBuddy、ASM或CGLIB这类库直接在运行时生成字节码。

以ByteBuddy为例,代码示例:

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.matcher.ElementMatchers;

import java.lang.reflect.Method;

public class ByteBuddyDynamicClass {
    public static void main(String[] args) throws Exception {
        // 生成Invoice类
        DynamicType.Unloaded<?> invoiceType = new ByteBuddy()
                .subclass(Object.class)
                .name("com.example.Invoice")
                .defineMethod("customer", void.class, ElementMatchers.PUBLIC)
                .withParameter(String.class)
                .intercept(FixedValue.nullValue())
                .defineMethod("project", void.class, ElementMatchers.PUBLIC)
                .withParameter(String.class)
                .intercept(FixedValue.nullValue())
                .defineMethod("cost", void.class, ElementMatchers.PUBLIC)
                .withParameter(String.class)
                .intercept(FixedValue.nullValue())
                .make();

        // 加载并实例化
        Class<?> invoiceClazz = invoiceType.load(ByteBuddyDynamicClass.class.getClassLoader()).getLoaded();
        Object invoice = invoiceClazz.getDeclaredConstructor().newInstance();
        invoiceClazz.getMethod("customer", String.class).invoke(invoice, "C001");

        // 生成PO类
        DynamicType.Unloaded<?> poType = new ByteBuddy()
                .subclass(Object.class)
                .name("com.example.PO")
                .defineMethod("date", void.class, ElementMatchers.PUBLIC)
                .withParameter(String.class)
                .intercept(FixedValue.nullValue())
                .defineMethod("amount", void.class, ElementMatchers.PUBLIC)
                .withParameter(String.class)
                .intercept(FixedValue.nullValue())
                .make();

        Class<?> poClazz = poType.load(ByteBuddyDynamicClass.class.getClassLoader()).getLoaded();
        Object po = poClazz.getDeclaredConstructor().newInstance();
        poClazz.getMethod("date", String.class).invoke(po, "2024-05-20");
    }
}

Maven依赖:

<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <version>1.14.11</version>
</dependency>

总结

  • 动态代理适合快速实现方法拦截逻辑,无需额外依赖;字节码库适合生成独立的、可持久化的类(可将生成的字节码写入文件保存)。
  • 两种方案都支持运行时生成类,无需提前存在类文件。

内容的提问来源于stack exchange,提问作者Java Learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 17:06:22