一文理解Janino:动态编译Java代码的神器

本文介绍了Janino,一个轻量级的Java编译器,展示了如何动态编译并执行Java代码片段。文章详细讲解了基本使用步骤,并提到了其在Flink中的应用实例。然而,Janino不支持Java8以上特性,对于复杂场景可能需考虑其他工具如ASM和Javassist。

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

01 引言

Janino是一个开源的轻量级Java编译器,它可以执行Java代码片段、类、方法等,而无需通过javac编译。这个框架的好处是,可以调用API去动态编译并执行传入的java字符串,且整个编译过程可以做到无感知。

02 Janino的基本使用

需求:现在期望通过输入一个类定义的java字符串(内容逻辑为输出Hello World),然后使用Janino去动态编译并执行。

首先,需要在项目中添加Janino依赖,可以通过MavenGradle添加,以下是使用maven的方式添加:

<dependency>
  <groupId>org.codehaus.janino</groupId>
  <artifactId>janino</artifactId>
  <version>3.1.6</version>
</dependency>

接着可以写janino相关的代码,内容如下:

/**
 * Janino演示
 *
 * @author : YangLinWei
 * @createTime: 2024/1/22 18:50
 * @version: 1.0.0
 */
public class JaninoTest {

    public static void main(String[] args) throws Exception {
        // 类定义
        String classDef = "public class HelloWorld { public static void helloWorld() { System.out.println(\"Hello, world!\"); } }";

        // 使用janino动态编译字符串并加载进类加载器
        SimpleCompiler sc = new SimpleCompiler();
        sc.cook(classDef);
        Class<?> clazz = sc.getClassLoader().loadClass("HelloWorld");

        // 使用janino执行
        clazz.getMethod("helloWorld").invoke(null);
    }
}

运行:

在这里插入图片描述

可以看到,我们通过动态传入类定义的字符串,使用Janino即可以实现动态编译并运行了。


其实在很多开源项目中都有Janino的影子,例如 Flink 中protobuf-format代码中的PbCodegenUtils实现(RowDataprotobuf二进制字节流的转换):

在这里插入图片描述

Janino编译逻辑:

在这里插入图片描述

03 文末

Janino是一款强大而易用的Java动态编译工具,用途非常广泛:可以用它来编译并执行Java代码片段,也可以用它来动态生成和编译整个Java类。但它也有自己的局限性:不支持Java 8及以上特性,如stream和lambda,也不能直接操作字节码。因此,对于需要复杂逻辑或操作字节码的任务,你可能需要查看其他动态编译工具(例如:ASM Javassist CGLIB等)。在选择使用Janino之前,需要确保它可以满足已有的应用场景和需求。

谢谢大家的阅读,希望能帮助到大家,本文完!

Janino是一个用Java实现的轻量级的动态编译器,可以在运行时动态的编译Java代码。下面是一个Java中使用Janino动态编译指定文件夹的示例代码: ```java import org.codehaus.janino.Compiler; import org.codehaus.janino.util.resource.DirectoryResourceFinder; import java.io.File; import java.io.IOException; public class JaninoDynamicCompiler { public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException { // 指定要编译的Java代码所在的文件夹 File sourceDir = new File("src/main/java/example"); // 创建一个Janino编译器对象 Compiler compiler = new Compiler(); // 设置编译器的编译选项 compiler.setDebuggingInformation(true, true, true); // 设置编译器的类加载器 ClassLoader classLoader = JaninoDynamicCompiler.class.getClassLoader(); compiler.setClassLoader(classLoader); // 设置编译器的资源查找器 DirectoryResourceFinder resourceFinder = new DirectoryResourceFinder(sourceDir); compiler.setSourceFinder(resourceFinder); // 编译Java代码 compiler.compile(sourceDir.listFiles()); // 加载编译生成的类 Class<?> clazz = classLoader.loadClass("example.HelloWorld"); // 创建类的实例并调用方法 Object instance = clazz.newInstance(); clazz.getMethod("sayHello").invoke(instance); } } ``` 以上代码中,我们首先指定要编译的Java代码所在的文件夹,然后创建了一个Janino编译器对象,并设置了编译器的编译选项、类加载器和资源查找器。接着调用编译器的`compile()`方法对Java代码进行编译。最后,我们加载编译生成的类,创建类的实例并调用方法。这样我们就可以在运行时动态的编译Java代码了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值