原来user.dir竟然会影响classpath的值

起因:使用脚本启动,脚本设置了classpath的路径为当前路径。但是从tomcat日志打印来看,扫描的不仅仅是当前路径,而是主目录下所有的文件夹都被扫描。导致项目启动异常缓慢。classpath设置如下:

set CLASSPATH=.;

当项目启动,查看APPClassLoader的url。按理来说“.”代表当前目录,也就是脚本执行的目录,是在bin目录下面。但是APPClassLoader的url却是主目录。我百思不得其解,只能翻JDK的源码看看AppClassLoader怎么加载它的URL。那么下面就跟我一起带着问题来看看答案吧。

以JDK 8为例,AppClassLoader的源码位于sun.misc.Launcher#AppClassLoader。

static class AppClassLoader extends URLClassLoader {

    static {
        ClassLoader.registerAsParallelCapable();
    }

    public static ClassLoader getAppClassLoader(final ClassLoader extcl)
        throws IOException
    {
        //在脚本中设置的值,在这个方法中可以拿到。此时s=".";
        final String s = System.getProperty("java.class.path");
        final File[] path = (s == null) ? new File[0] : getClassPath(s);

       
        return AccessController.doPrivileged(
            new PrivilegedAction<AppClassLoader>() {
                public AppClassLoader run() {
                //设置url的关键代码,也就是此时的重点关注对象
                URL[] urls =
                    (s == null) ? new URL[0] : pathToURLs(path);
                return new AppClassLoader(urls, extcl);
            }
        });
    }

从上方的代码可以看到pathToURLs(path)是把"."转化为路径的关键代码。那么接下看看这个方法干了啥吧。

private static URL[] pathToURLs(File[] path) {
    URL[] urls = new URL[path.length];
    for (int i = 0; i < path.length; i++) {
       //好吧,关键代码又来到了getFileURL这个方法
        urls[i] = getFileURL(path[i]);
    }
    return urls;
}
static URL getFileURL(File file) {
        //在这个方法中路径“.”,发生了变化。
        file = file.getCanonicalFile();
       return ParseUtil.fileToEncodedURL(file);
}

代码一层一层的绕,为了方便阅读,我搞点伪代码。下方是伪代码示例:

public File getCanonicalFile() throws IOException {
      //好吧url的处理来到getCanonicalPath方法
    String canonPath = getCanonicalPath();
    return new File(canonPath, fs.prefixLength(canonPath));
}
public String getCanonicalPath() throws IOException {
      //fs.resolve(this)这是重点关注对象
    return fs.canonicalize(fs.resolve(this));
}

现在从fs.resolve(this)看看url的变化

public String resolve(File f) {
    //此时这个path的值是“.”
    String path = f.getPath();
    //pl的结果是0,那就跳到对应的if去吧
    int pl = f.getPrefixLength();
    if ((pl == 2) && (path.charAt(0) == slash))
        return path;                        /* UNC */
    if (pl == 3)
        return path;                        /* Absolute local */
        //转化为路径的关键代码出现了,getUserPath()
    if (pl == 0)
        return getUserPath() + slashify(path); /* Completely relative */
}

来看看上方getUserPath()的实现吧

private String getUserPath() {
    return normalize(System.getProperty("user.dir"));
}

意思就是如果我们的classpath=.;那么如果我们在环境变量设置user.dir的值。classpath的值就变成了user.dir的值。很不巧我们的启动脚本找到关于user.dir的赋值:set -Duser.dir="主目录"。这就解释了为什么classpath设置了“.”而APPClassLoader的url却变成了主目录。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文安初心忆往昔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值