Java 运行时动态生成类(动态编译)与 生产环境报错处理(Deprecated)

本文介绍如何在SpringBoot项目中动态生成类,并提供了一个Person类的示例,该类具有抽象方法sayHello。通过使用com.itranswarp.compiler库,文章展示了如何在运行时创建Person的子类并调用其方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Deprecated:这种方式在SpringBoot项目中不太好用,打成jar包后会有很多问题

请参考:https://blog.csdn.net/zhaohongfei_358/article/details/121383997

案例说明

我们有一个Person类:

package test;

import lombok.Data;

@Data
public abstract class Person {

    private String name;

    public abstract void sayHello();
}

Person类有一个抽象方法 sayHello,但是具体有哪些Person并不知道,需要配置在数据库中,然后动态进行生成Person的子类。

动态生成类工具类

<dependency>
    <groupId>com.itranswarp</groupId>
    <artifactId>compiler</artifactId>
    <version>1.0</version>
</dependency>

如果是SpringBoot项目,最好加上

<dependency>
    <groupId>com.sun</groupId>
    <artifactId>tools</artifactId>
    <version>1.8</version>
    <scope>system</scope>
    <systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>

工具类代码如下:

package test;

import com.itranswarp.compiler.JavaStringCompiler;

import java.util.Map;

public class CompilerUtil {

    public static Class generateClass(String javaFilename, String packageName, String javaCode) throws Exception {

        JavaStringCompiler compiler = new JavaStringCompiler();

        String prefix = String.format("package %s;", packageName);

        Map<String, byte[]> map = compiler.compile(javaFilename + ".java", prefix + "\n" + javaCode);

        return compiler.loadClass(packageName + "." + javaFilename, map);
    }
}

动态生成类

package test;

import com.itranswarp.compiler.JavaStringCompiler;

import java.util.Map;

public class CompilerUtil {

    public static Class generateClass(String javaFilename, String packageName, String javaCode) throws Exception {

        JavaStringCompiler compiler = new JavaStringCompiler();

        String prefix = String.format("package %s;", packageName);

        Map<String, byte[]> map = compiler.compile(javaFilename + ".java", prefix + "\n" + javaCode);

        return compiler.loadClass(packageName + "." + javaFilename, map);
    }

    public static void main(String[] args) throws Exception {
        String teacherCode = "public class Teacher extends Person {\n" +
                "\n" +
                "    @Override\n" +
                "    public void sayHello() {\n" +
                "        System.out.println(\"My name is \" + getName() + \", I am a teacher\");\n" +
                "    }\n" +
                "}\n";

        Class teacherClass = generateClass("Teacher", "test", teacherCode);
        Person person = (Person) teacherClass.newInstance();
        person.setName("Tom");
        person.sayHello();
    }
}
My name is Tom, I am a teacher

生产环境报错

打Jar包后(生产环境)报错:错误: 找不到符号

本地运行很好,到生产上,就报:cannot find symbol

java.lang.RuntimeException: Compilation failed.
	at com.itranswarp.compiler.JavaStringCompiler.compile(JavaStringCompiler.java:46)
	at com.fsk.ehr.utils.SalaryUtil.getOrGenerateSalaryComputerClass(SalaryUtil.java:51)

解决方案:

参考文档:https://github.com/michaelliao/compiler/issues/5

25行报空指针

	public JavaStringCompiler() {
		this.compiler = ToolProvider.getSystemJavaCompiler();
		this.stdManager = compiler.getStandardFileManager(null, null, null); // 报空指针
	}

解决方案

查看生产环境是否装了jre,没有装jdk,如果不装jdk,是没法使用动态编译功能的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iioSnail

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值