# 动态编译加载执行工具 **Repository Path**: xddcode/loader-util ## Basic Information - **Project Name**: 动态编译加载执行工具 - **Description**: 在运行期动态加载、编译、执行工具,包括( 1.DynamicBean 动态加载Bean并执行; 2.DynamicClass 动态编译加载Class并执行; 3.DynamicJar 动态加载外部jar到项目中; 4.DynamicGroovy 动态编译加载Groovy并执行; 5.DynamicController 动态编译加载Controller并执行; 6.proxy 动态代理切面; ) - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 24 - **Created**: 2024-02-21 - **Last Updated**: 2024-03-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # loader-util 动态编译、加载、执行工具 [![](https://jitpack.io/v/com.gitee.wb04307201/loader-util.svg)](https://jitpack.io/#com.gitee.wb04307201/loader-util) [![star](https://gitee.com/wb04307201/loader-util/badge/star.svg?theme=dark)](https://gitee.com/wb04307201/loader-util) [![fork](https://gitee.com/wb04307201/loader-util/badge/fork.svg?theme=dark)](https://gitee.com/wb04307201/loader-util) [![star](https://img.shields.io/github/stars/wb04307201/loader-util)](https://github.com/wb04307201/loader-util) [![fork](https://img.shields.io/github/forks/wb04307201/loader-util)](https://github.com/wb04307201/loader-util) ## 代码示例 1. 使用[动态编译加载执行工具](https://gitee.com/wb04307201/loader-util)实现的[动态编译加载执行工具示例代码](https://gitee.com/wb04307201/loader-util-test) 2. 使用[动态调度](https://gitee.com/wb04307201/dynamic-schedule-spring-boot-starter)、[消息中间件](https://gitee.com/wb04307201/message-spring-boot-starter)、[动态编译加载执行工具](https://gitee.com/wb04307201/loader-util)、[实体SQL工具](https://gitee.com/wb04307201/sql-util)实现的[在线编码、动态调度、发送钉钉群消息、快速构造web页面Demo](https://gitee.com/wb04307201/dynamic-schedule-demo) ## 第一步 增加 JitPack 仓库 ```xml jitpack.io https://jitpack.io ``` ## 第二步 引入jar 1.1.0版本后升级到jdk17 SpringBoot3+ ```xml com.gitee.wb04307201 loader-util 1.1.3 ``` ## 第三步 如何使用 ## 1. DynamicBean 动态编译加载Bean并执行 > 使用DynamicBean需要配置@ComponentScan,包括cn.wubo.loader.util.SpringContextUtils文件 ```java @GetMapping(value = "/test/bean") public String testBean(){ String javaSourceCode = "package cn.wubo.loader.util;\n" + "\n" + "public class TestClass {\n" + " \n" + " public String testMethod(String name){\n" + " return String.format(\"Hello,%s!\",name);\n" + " }\n" + "}"; String fullClassName = "cn.wubo.loader.util.TestClass"; String methodName = "testMethod"; String beanName = DynamicBean.init(DynamicClass.init(javaSourceCode,fullClassName)).load(); return (String) MethodUtils.invokeBean(beanName,methodName,"world"); } ``` ## 2. DynamicClass 动态编译加载Class并执行 ```java @GetMapping(value = "/test/class") public String testClass(){ String javaSourceCode = "package cn.wubo.loader.util;\n" + "\n" + "public class TestClass {\n" + " \n" + " public String testMethod(String name){\n" + " return String.format(\"Hello,%s!\",name);\n" + " }\n" + "}"; String fullClassName = "cn.wubo.loader.util.TestClass"; String methodName = "testMethod"; DynamicClass dynamicClass = DynamicClass.init(javaSourceCode, fullClassName).compiler(); Class clasz = dynamicClass.load(); return (String) MethodUtils.invokeClass(clasz, methodName, "world"); } ``` ## 3. DynamicJar 动态加载外部jar并执行 ```java @GetMapping(value = "/test/jar") public String testJar(){ Class clasz = DynamicJar.init("D:\\maven-repository\\repository\\cn\\hutool\\hutool-all\\5.3.2\\hutool-all-5.3.2.jar").load("cn.hutool.core.util.IdUtil"); return (String) MethodUtils.invokeClass(clasz, "randomUUID"); } ``` ## 4. DynamicGroovy 动态编译加载Groovy并执行 ```java @GetMapping(value = "/loadAndInvokeGroovy") public String loadAndInvokeGroovy() { String javaSourceCode = "package cn.wubo.loader.util;\n" + "\n" + "public class TestClass {\n" + " \n" + " public String testMethod(String name){\n" + " return String.format(\"Hello,%s!\",name);\n" + " }\n" + "}"; String methodName = "testMethod"; Class clasz = DynamicGroovy.init(javaSourceCode).load(); return (String) MethodUtils.invokeClass(clasz, methodName, "world"); } ``` ## 5. DynamicController 动态编译加载Controller并执行 ```java @GetMapping(value = "/loadController") public String loadController() { String fullClassName = "cn.wubo.loaderutiltest.DemoController"; String javaSourceCode = """ package cn.wubo.loaderutiltest; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "test") public class DemoController { @GetMapping(value = "hello") public User hello(@RequestParam(value = "name") String name) { return new User(name); } @Data @AllArgsConstructor @NoArgsConstructor public static class User { private String name; } } """; return DynamicController.init(DynamicClass.init(javaSourceCode, fullClassName)).load(); } ``` ```http request GET http://localhost:8080/test/hello?name=world Accept: application/json Hello,world! ``` ## 6. proxy 动态代理切面 ```java @GetMapping(value = "/testAspect") public String testAspect() throws InstantiationException, IllegalAccessException { String javaSourceCode = "package cn.wubo.loader.util;\n" + "\n" + "public class TestClass {\n" + " \n" + " public String testMethod(String name){\n" + " return String.format(\"Hello,%s!\",name);\n" + " }\n" + "}"; String fullClassName = "cn.wubo.loader.util.TestClass"; String methodName = "testMethod"; DynamicClass dynamicClass = DynamicClass.init(javaSourceCode, fullClassName).compiler(); Class clasz = dynamicClass.load(); Object obj = MethodUtils.proxy(clasz.newInstance()); return (String) MethodUtils.invokeClass(obj, methodName, "world"); } ``` 输出示例 ```text 2023-04-08 21:22:14.174 INFO 32660 --- [nio-8080-exec-1] cn.wubo.loader.util.aspect.SimpleAspect : SimpleAspect before cn.wubo.loader.util.TestClass testMethod 2023-04-08 21:22:14.175 INFO 32660 --- [nio-8080-exec-1] cn.wubo.loader.util.aspect.SimpleAspect : SimpleAspect after cn.wubo.loader.util.TestClass testMethod 2023-04-08 21:22:14.175 INFO 32660 --- [nio-8080-exec-1] cn.wubo.loader.util.aspect.SimpleAspect : StopWatch 'cn.wubo.loader.util.TestClass testMethod': running time = 65800 ns ``` 可以通过继承IAspect接口实现自定义切面,并通过MethodUtils.proxy(Class clazz, Class aspectClass)方法调用切面 ## DynamicClass如何在服务器上运行 因为本地和服务器的差异导致classpath路径不同, 进而使服务上动态编译class时会发生找不到import类的异常, 因此需要对maven编译配置和启动命令做出一定的修改 ### 1. maven编译配置增加如下部分 ```xml org.apache.maven.plugins maven-jar-plugin true lib/ cn.wubo.loaderutiltest.LoaderUtilTestApplication org.apache.maven.plugins maven-dependency-plugin copy-dependencies package copy-dependencies ${project.build.directory}/lib false false runtime ``` ### 2. 执行编译命令,会在jar包的同级目录下生成lib文件夹存放依赖包 ![img.png](img.png) ### 3. 将jar包和lib文件夹上到服务器,并在启动命令中增加`-Dloader.path=lib/` ```shell java -jar -Dloader.path=lib/ loader-util-test-0.0.1-SNAPSHOT.jar ```