Liquor Java 动态编译器。支持完整的 Java 语法及各版本特性（具体看运行时版本）。编译特点：

* 可以指定父类加载器（默认，为当前线程内容类加载器）
* 可以单个类编译
* 可以多个类同时编译
* 可以增量编译
* 非线程安全。多线程时，要注意锁控制。
* <mark>编译的性能，可以按“次”计算。尽量多类编译一次。</mark>
* 可以与主项目一起调试

编译后，从 ClassLoader 获取类。


### 1、入门示例


```java
public class DemoApp {
    public static void main(String[] args) throws Exception{
        //可以复用（可以，不断的增量编译）
        DynamicCompiler compiler = new DynamicCompiler();
        
        String className = "HelloWorld";
        String classCode = "public class HelloWorld { " +
                "   public static void helloWorld() { " +
                "       System.out.println(\"Hello world!\"); " +
                "   } " +
                "}";
        
        //添加源码（可多个）并 构建
        compiler.addSource(className, classCode).build();
        
        //构建后，仍可添加不同类的源码再构建

        Class<?> clazz = compiler.getClassLoader().loadClass(className);
        clazz.getMethod("helloWorld").invoke(null);
    }
}
```

### 2、运行时调试方案说明

* 为源码创建一个对应的 `.java` 文件（如果直接读取 `.java` 文件的，就省了）
* `.java` 文件需放到宿主项目里。比如，根目录下建个 dynamic 的普通目录放这个调试文件。
* 打开这个文件，设好断点。就可以和宿主项目一起调试了。


具体可参考示例模块：[demo_dynamic_compiling_and_debugging_solon](https://gitee.com/noear/liquor/tree/main/demo_dynamic_compiling_and_debugging_solon)


Bilibili 视频演示：[《Liquor Java 动态编译神器 - 随心所欲的动态编译与调试》](https://www.bilibili.com/video/BV198QyYQEmw/)

### 3、多类编译示例

可以把需要编译的代码收集后，多类编译一次。这样，时间更少。

```java
public class DemoApp {
    @Test
    public void test() throws Exception{
        DynamicCompiler compiler = new DynamicCompiler();

        compiler.addSource("com.demo.UserDo", "package com.demo;\n" +
                "import java.util.HashMap;\n\n"+
                "public class UserDo{\n" +
                "    private String name;\n" +
                "\n" +
                "    public String getName() {\n" +
                "        return name;\n" +
                "    }\n" +
                "    \n" +
                "    public UserDo(String name) {\n" +
                "        this.name = name;\n" +
                "    }\n" +
                "}");

        compiler.addSource("com.demo.IUserService", "package com.demo;\n" +
                "public interface IUserService {\n" +
                "    UserDo getUser(String name);\n" +
                "}");

        compiler.addSource("com.demo.UserService", "package com.demo;\n" +
                "public class UserService implements IUserService {\n" +
                "    @Override\n" +
                "    public UserDo getUser(String name) {\n" +
                "        return new UserDo(name);\n" +
                "    }\n" +
                "}");

        compiler.build();

        Class<?> clz = compiler.getClassLoader().loadClass("com.demo.UserService");
        Object obj = clz.newInstance();

        System.out.println(obj);
        System.out.println(obj.getClass());

        Object objUser = clz.getMethods()[0].invoke(obj, "noear");
        System.out.println(objUser);
        System.out.println(objUser.getClass());
    }
}
```




### 4、类加载器的切换

类加载器 ClassLoader 内部是基于 hash 管理类的，所以相同的类名只能有一个。。。如果我们需要对相同的类名进行编译。可以采用两种方式：

* 重新实例化动态编译器（DynamicCompiler）
* 通过切换类加载器（也可以新建类加载器）。应用时，可建立识别体系，识别是重要换新的类加载器？


```java
ClassLoader cl_old = compiler.getClassLoader();
ClassLoader cl_new = compiler.newClassLoader();

compiler.setClassLoader(cl_new);
compiler.addSource("...");
compiler.build();

//...用完，可以换回来 //只是示例
compiler.setClassLoader(cl_old);
```


