加载指定路径下jar包的class

加载指定路径下jar包的class

/**
 * @Date: 2023/8/28 9:34
 * 指定目录下加载一般的 jar 包加载 class
 * 处理不了 jar中打包了其他 jar的 class, 如 spring boot repackage 的 jar 包
 *
 */
@Slf4j
public class JarProvider extends ClassLoader {

    private static final String JAR_SUFFIX = ".jar";
    private static final String CLZ_SUFFIX = ".class";
    private List<File> files;
    private List<FatJar> cache;
    private ReentrantLock lock = new ReentrantLock();


    public JarProvider(ClassLoader parent, List<String> dirs) {
        super(parent);
        this.files = new ArrayList<>();
        dirs.forEach(dir -> files.add(new File(dir)));
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        List<FatJar> fatJars = getAllFatJars();
        //将 class名替换成 文件路径访问 class,即
        //a.b.c.D -> a/b/c/D.class
        String className = name.replace(".", "/").concat(CLZ_SUFFIX);
        for (FatJar fatJar : fatJars) {
            logLoadResources(fatJar);
            JarEntry jarEntry = fatJar.getJar().getJarEntry(className);
            if (jarEntry == null) {
                continue;
            }
            log.info("load jar info: {}", jarEntry.getName());
            try {
                String fileUrl = "jar:file:" + fatJar.getFile().getAbsoluteFile() + "!/" + className;
                log.info("load class file url: {}", fileUrl);
                URL url = new URL(fileUrl);
                //读取 jar 包中的 class文件
                try (BufferedInputStream bis = new BufferedInputStream(url.openStream()); ByteArrayOutputStream ois = new ByteArrayOutputStream()) {
                    int len;
                    byte[] buf = new byte[1024];
                    while ((len = bis.read(buf)) != -1) {
                        ois.write(buf,0,len);
                    }
                    byte[] data = ois.toByteArray();
                    return defineClass(name, data, 0, data.length);
                }
            } catch (IOException e) {
                log.error("find class error:{}", className, e);
            }

        }
        throw new ClassNotFoundException("can not find class: " + name);
    }

    private static void logLoadResources(FatJar fatJar) {
        Enumeration<JarEntry> entries = fatJar.getJar().entries();
        while (entries.hasMoreElements()) {
            JarEntry jarEntry = entries.nextElement();
            //这里有entry 可能 是 .class,也可能是 .jar,还有可能是其他类型的文件 !!
            log.info("load class: {}", jarEntry.getName());
        }
    }

    /**
     * 加载 其他类型的 资源文件
     * @param name
     *         The resource name
     *
     * @return
     */
    @Override
    protected URL findResource(String name) {
        List<FatJar> fatJars = getAllFatJars();
        for (FatJar fatJar : fatJars) {
            logLoadResources(fatJar);
            JarEntry jarEntry = fatJar.getJar().getJarEntry(name);
            if (jarEntry != null) {
                log.info("load jar info: {}", jarEntry.getName());
                try {
                    return new URL("jar:file:" + fatJar.getFile().getAbsoluteFile() + "!/" + name);
                } catch (MalformedURLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return null;
    }

    private List<FatJar> getAllFatJars() {
        if (cache != null) {
            return cache;
        }
        lock.lock();
        try {
            if (cache == null) {
                cache = doGetAllFatJars();
            }
        } finally {
            lock.unlock();
        }
        return cache;
    }

    private List<FatJar> doGetAllFatJars() {
        List<FatJar> result = new ArrayList<>();
        for (File path : files) {
            //处理目录
            if (path.exists() && path.isDirectory()) {
                String[] list = path.list((dir, name) -> name.endsWith(JAR_SUFFIX));
                for (String s : list) {
                    File file = new File(path, s);
                    try {
                        FatJar fatJar = new FatJar(new JarFile(file), file);
                        result.add(fatJar);
                        log.info("load jar: {}", file);
                    } catch (IOException e) {
                        log.error("load jar error: {}", file);
                    }
                }
            }
        }
        return result;
    }


    /**
     * 加载 jar 包中其他类型的文件 如 properties and so on...
     * @param name
     *         The resource name
     *
     * @return
     * @throws IOException
     */
    @Override
    protected Enumeration<URL> findResources(String name) throws IOException {
        List<URL> results =new LinkedList<>();
        List<FatJar> fatJars = getAllFatJars();
        for (FatJar fatJar : fatJars) {
            logLoadResources(fatJar);
            JarEntry jarEntry = fatJar.getJar().getJarEntry(name);
            if (jarEntry != null) {
                log.info("load jar info: {}", jarEntry.getName());
                results.add(new URL("jar:file:" + fatJar.getFile().getAbsoluteFile() + "!/" + name));
            }
        }
        final Iterator<URL> iterator = results.iterator();
        return new Enumeration<URL>() {
            @Override
            public boolean hasMoreElements() {
                return iterator.hasNext();
            }

            @Override
            public URL nextElement() {
                return iterator.next();
            }
        };
    }

    @Data
    @AllArgsConstructor
    public static class FatJar {
        private JarFile jar;
        private File file;

    }
}

测试:

public class JarProviderTest {


    @Test
    public void loadJar() throws Exception {
        List<String> list = Arrays.asList("D:\\demo-sample\\target\\");
        JarProvider jarProvider = new JarProvider(JarProviderTest.class.getClassLoader(), list);
        Class<?> aClass = jarProvider.loadClass("org.example.sample.hello.Hello");
        Object o = aClass.newInstance();
        Method say = aClass.getMethod("say", String.class);
        say.invoke(o,"tom");
        System.out.println(aClass.getName());
    }

    @Test
    public void loadResoruceTest() throws Exception {
        List<String> list = Arrays.asList("D:\\demo-sample\\target\\");
        JarProvider jarProvider = new JarProvider(JarProviderTest.class.getClassLoader(), list);
        Enumeration<URL> resources = jarProvider.getResources("test.properties");
        Properties properties = new Properties();
        properties.load(resources.nextElement().openStream());
        String property = properties.getProperty("a.b");
        System.out.println(property);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值