吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1243|回复: 1
收起左侧

[Java 转载] 项目打包jar并动态编译外部Java文件

[复制链接]
zzzkc 发表于 2021-12-2 17:02
本帖最后由 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   

免费评分

参与人数 1吾爱币 +7 热心值 +1 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

wencun 发表于 2021-12-4 11:40
收藏了多谢大佬
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 10:00

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表