资讯专栏INFORMATION COLUMN

分享代码片段:将指定位置的war包加入classpath的classloader实现

HelKyle / 1434人阅读

摘要:一般来说,可以被加入到中的东西,除了文件夹,就只有包了但有的时候,我们可能希望将一个已经存在的包里面的所有文件加入,这包括下的所有文件和下的所有包直接将该包加入中是不能达到上述目的的,那么就可以使用下面这个工具达到此目的用法

一般来说,可以被加入到java classpath中的东西,除了文件夹,就只有jar包了;
但有的时候,我们可能希望将一个已经存在的war包里面的所有class文件加入classpath,这包括/WEB-INF/classes下的所有class文件和/WEB-INF/lib下的所有jar包;
直接将该war包加入classpath中是不能达到上述目的的,那么就可以使用下面这个工具达到此目的:

package kilim.tools;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * classloader which allows user to set a war archive path to be included in the
 * classpath dynamically.
 * 
 * @author pf_miles
 * 
 */
public class WarPathClassLoader extends URLClassLoader {

    private boolean warPathSet;
    private String explodedWarPath;

    public WarPathClassLoader(ClassLoader parent) {
        super(new URL[0], parent);
    }

    public void setWarPath(String path) {
        if (this.warPathSet)
            throw new RuntimeException("War archive path already set. Kilim-fiber tools cannot weave multiple war archives at the same time.");
        File w = new File(path);
        if (w.exists()) {
            final File dir;
            try {
                warPathSet = true;
                // 0.create a temp dir
                dir = createTempDirectory(w.getName());
                // 1.extract the war to the temp dir
                extractTo(w, dir);
                // 2.add /WEB-INF/classes to cp
                File clses = locateFile(dir, "WEB-INF", "classes");
                super.addURL(clses.toURI().toURL());
                // 3.add all jars under /WEB-INF/lib/ to cp
                File lib = locateFile(dir, "WEB-INF", "lib");
                File[] jars = lib.listFiles();
                for (File j : jars)
                    super.addURL(j.toURI().toURL());
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
            // delete temp dir when exit
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                public void run() {
                    if (dir != null) {
                        delRecur(dir);
                    }
                }
            }));
            this.explodedWarPath = dir.getAbsolutePath();
        } else {
            throw new RuntimeException("File not exists: " + path);
        }
    }

    private static void delRecur(File file) {
        if (!file.exists())
            return;
        if (file.isDirectory()) {
            // 1.del sub files first
            for (File s : file.listFiles())
                delRecur(s);
            // 2.del the dir
            file.delete();
        } else {
            file.delete();
        }
    }

    private static File locateFile(File dir, String... paths) {
        File cur = dir;
        outter: for (String p : paths) {
            File[] all = cur.listFiles();
            for (File f : all) {
                if (p.equals(f.getName())) {
                    cur = f;
                    continue outter;
                }
            }
            throw new RuntimeException("No path named "" + p + "" found in file: " + cur.getAbsolutePath());
        }
        return cur;
    }

    // extract content of "w" to dir
    private static void extractTo(File w, File dir) {
        String dirPath = dir.getAbsolutePath();
        if (!dirPath.endsWith("/"))
            dirPath += "/";
        try {
            JarFile jar = new JarFile(w);
            Enumeration e = jar.entries();
            byte[] buf = new byte[4096];

            while (e.hasMoreElements()) {
                JarEntry file = (JarEntry) e.nextElement();
                File f = new File(dirPath + file.getName());

                if (file.isDirectory()) { // if its a directory, create it
                    f.mkdirs();
                    continue;
                }

                InputStream is = jar.getInputStream(file);
                FileOutputStream fos = ensureOpen(f);

                // write contents of "is" to "fos"
                for (int avai = is.read(buf); avai != -1; avai = is.read(buf)) {
                    fos.write(buf, 0, avai);
                }
                fos.close();
                is.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // if does not exist, create one, and ensure all parent dirs exist
    private static FileOutputStream ensureOpen(File f) throws IOException {
        if (!f.exists()) {
            File p = f.getParentFile();
            if (p != null && !p.exists())
                p.mkdirs();
            f.createNewFile();
        }
        return new FileOutputStream(f);
    }

    private static File createTempDirectory(String dirName) {
        final File temp;

        try {
            temp = File.createTempFile(dirName, Long.toString(System.currentTimeMillis()));
            temp.deleteOnExit();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        if (!(temp.delete())) {
            throw new RuntimeException("Could not delete temp file: " + temp.getAbsolutePath());
        }

        if (!(temp.mkdir())) {
            throw new RuntimeException("Could not create temp directory: " + temp.getAbsolutePath());
        }

        return (temp);
    }

    /**
     * get the temporary directory path which contains the exploded war files
     */
    public String getExplodedWarPath() {
        if (this.explodedWarPath == null)
            throw new RuntimeException(""explodedWarPath" is null, maybe the war path is not set.");
        return this.explodedWarPath;
    }

}

用法:new一个WarPathClassLoader实例,然后调用setWarPath指定war包所在位置即可

gist地址:https://gist.github.com/pfmiles/2002fdace1caa247618b

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64418.html

相关文章

  • 深入Spring Boot:ClassLoader继承关系和影响

    摘要:的打包结构改动是这个引入的这个的本意是简化的继承关系,以一种直观的优先的方式来实现,同时打包结构和传统的包应用更接近。目前的继承关系带来的一些影响有很多用户可能会发现,一些代码在里跑得很好,但是在实际部署运行时不工作。 前言 对spring boot本身启动原理的分析,请参考:http://hengyunabc.github.io/s... Spring boot里的ClassLoad...

    lifesimple 评论0 收藏0
  • 慕课网_《Spring Boot热部署》学习总结

    时间:2017年12月01日星期五说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com 教学源码:无 学习源码:https://github.com/zccodere/s... 第一章:课程介绍 1-1 课程介绍 热部署的使用场景 本地调式 线上发布 热部署的使用优点 无论本地还是线上,都适用 无需重启服务器:提高开发、调式效率、提升发布、运维效率、降低运维成本 前置...

    Channe 评论0 收藏0
  • Play framework源码解析 Part1:Play framework 介绍、项目构成及启动

    摘要:注本系列文章所用版本为介绍是个轻量级的框架,致力于让程序员实现快速高效开发,它具有以下几个方面的优势热加载。在调试模式下,所有修改会及时生效。抛弃配置文件。约定大于配置。 注:本系列文章所用play版本为1.2.6 介绍 Play framework是个轻量级的RESTful框架,致力于让java程序员实现快速高效开发,它具有以下几个方面的优势: 热加载。在调试模式下,所有修改会及时...

    Riddler 评论0 收藏0
  • 使用maven创建简单多模块 Spring Web项目

    摘要:第一次写技术文章,主要内容是使用创建一个简单的项目,如有操作或理解错误请务必指出,当谦虚学习。基本思想其实就是一个项目引用别的模块包,最终项目被打成包发布。 第一次写技术文章,主要内容是使用maven创建一个简单的SpringMVC WEB 项目,如有操作或理解错误请务必指出,当谦虚学习。做这一次的工作主要是因为想加强一下自己对Spring Web 项目的理解,因为平时都是直接写业务代...

    DevYK 评论0 收藏0
  • 【转】Javapackage和import机制

    摘要:比如说,就是复姓,名字为的类别则是复姓,名字为的类别。先介绍的机制基本原则需要将类文件切实安置到其所归属之所对应的相对路径下。把源代码文件,文件和其他文件有条理的进行一个组织,以供来使用。可以使用通配符,代表某下所有的,不包括子目录。 一些人用了一阵子的Java,可是对于 Java 的 package 跟 import 还是不太了解。很多人以为原始码 .java 文件中的 import...

    anRui 评论0 收藏0

发表评论

0条评论

HelKyle

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<