本帖最后由 zzzkc 于 2021-12-2 17:06 编辑
感谢 https://blog.csdn.net/shuaizai88/article/details/105016029 博主解决了动态编译Java代码过程中出现找不到依赖包的问题。其核心代码:[Java] 纯文本查看 复制代码 // 可执行jar的路径如:C:/Users/User/Desktop/xx/xx/project.jar
String jarBaseFile = MemoryClassLoader.getPath();
JarFile jarFile = new JarFile(new File(jarBaseFile));
// 获取项目中所依赖的jar包
List<JarEntry> entries = jarFile.stream().filter(jarEntry -> {
return jarEntry.getName().endsWith(".jar");
}).collect(Collectors.toList());
JarFile libTempJarFile = null;
List<JavaFileObject> onePackgeJavaFiles = null;
String packgeName = null;
// 遍历每一个引用的jar包
for (JarEntry entry : entries) {
libTempJarFile = jarFile.getNestedJarFile(jarFile.getEntry(entry.getName()));
if (libTempJarFile.getName().contains("tools.jar")) {
continue;
}
Enumeration<JarEntry> tempEntriesEnum = libTempJarFile.entries();
// 遍历每一个jar包中的class并缓存
while (tempEntriesEnum.hasMoreElements()) {
JarEntry jarEntry = tempEntriesEnum.nextElement();
String classPath = jarEntry.getName().replace("/", ".");
if (classPath.endsWith(".class") && jarEntry.getName().lastIndexOf("/") != -1) {
packgeName = classPath.substring(0, jarEntry.getName().lastIndexOf("/"));
onePackgeJavaFiles = CLASS_OBJECT_PACKAGE_MAP.containsKey(packgeName) ? CLASS_OBJECT_PACKAGE_MAP.get(packgeName) : new ArrayList<>();
onePackgeJavaFiles.add(new MemorySpringBootInfoJavaClassObject(jarEntry.getName().replace("/", ".").replace(".class", ""), new URL(libTempJarFile.getUrl(), jarEntry.getName()), javaFileManager));
CLASS_OBJECT_PACKAGE_MAP.put(packgeName, onePackgeJavaFiles);
}
}
} 不过有个问题,就是找不到项目自己编写的类,比如代码引用了项目的一个工具类,这时编译外部的Java文件就会报找不到这个工具类的错误。因此需要在上面基础做修改:[Java] 纯文本查看 复制代码 String jarBaseFile = MemoryClassLoader.getPath();
JarFile jarFile = new JarFile(new File(jarBaseFile));
// 解决找不到service、bean、util等自己写的class
insCacheClass(jarFile, true);
// 获取所引入的jar包
List<JarEntry> entries = jarFile.stream().filter(jarEntry -> jarEntry.getName().endsWith(".jar")).collect(Collectors.toList());
JarFile libTempJarFile;
// 遍历每一个引用的jar包
for (JarEntry entry : entries) {
libTempJarFile = jarFile.getNestedJarFile(jarFile.getEntry(entry.getName()));
if (libTempJarFile.getName().contains("tools.jar")) {
continue;
}
insCacheClass(libTempJarFile, false);
}
/**
* 从jar内遍历class并缓存
* [url=home.php?mod=space&uid=952169]@Param[/url] jarFile jar文件
* @param isProjectJar 是否本项目jar
*/
private void insCacheClass(JarFile jarFile, Boolean isProjectJar) {
Enumeration<JarEntry> tempEntriesEnum = jarFile.entries();
String packageName;
List<JavaFileObject> onePackageJavaFiles;
// 相关的class文件进行缓存
try {
while (tempEntriesEnum.hasMoreElements()) {
JarEntry jarEntry = tempEntriesEnum.nextElement();
String classPath = jarEntry.getName().replace("/", ".");
if (classPath.endsWith(".class") && jarEntry.getName().lastIndexOf("/") != -1) {
packageName = classPath.substring(0, jarEntry.getName().lastIndexOf("/"));
// jar项目
if (isProjectJar) {
if (packageName.contains("BOOT-INF.classes.")) {
packageName = packageName.replace("BOOT-INF.classes.", "");
}
}
onePackageJavaFiles = CLASS_OBJECT_PACKAGE_MAP.containsKey(packageName) ? CLASS_OBJECT_PACKAGE_MAP.get(packageName) : new ArrayList<>();
onePackageJavaFiles.add(new MemoryJavaClassObject(jarEntry.getName().replace("/", ".").replace(".class", ""),
new URL(jarFile.getUrl(), jarEntry.getName()), javaFileManager));
CLASS_OBJECT_PACKAGE_MAP.put(packageName, onePackageJavaFiles);
}
}
} catch (Exception e) {
e.printStackTrace();
}
} 这是基于打成jar包的形式,如果是war包用tomcat运行的话,应该也是获取依赖包的路径再进行遍历缓存。修改后的项目地址: https://gitee.com/zzzkc/jar-project 外部Java文件的packageName对应 PathUtils.java 中的PACKAGE_NAME;[Java] 纯文本查看 复制代码 private static final String ROOT_PATH = "C:/Users/User/Desktop/";
private static final String PACKAGE_NAME = "deploy.clz"; 测试:在桌面创建deploy/clz文件夹,将项目中的OnService文件复制到deploy/clz中并修改文件package deploy.clz测试数据:[SQL] 纯文本查看 复制代码 SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(20) NOT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`age` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '张强', '43');
INSERT INTO `sys_user` VALUES (2, '李锦', '21');
SET FOREIGN_KEY_CHECKS = 1; 最后打包jar,运行并访问:127.0.0.1:9001/deploy/OnService/getList 或者 http://127.0.0.1:9001/deploy/OnService/getOne?id=1 |