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

文章探讨了一个Java应用在启动时,classpath设置为.,但Tomcat的日志显示扫描了主目录所有文件夹的问题。原因是Java的AppClassLoader在处理.时会转换为user.dir系统属性所指的路径,若在启动脚本中设置了user.dir为主目录,则导致扫描该目录。解决办法是确保正确设置classpath。
摘要由CSDN通过智能技术生成

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

 

ini

复制代码

set CLASSPATH=.;

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

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

 

scala

复制代码

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)是把"."转化为路径的关键代码。那么接下看看这个方法干了啥吧。

 

ini

复制代码

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; }

 

scss

复制代码

static URL getFileURL(File file) { //在这个方法中路径“.”,发生了变化。 file = file.getCanonicalFile(); return ParseUtil.fileToEncodedURL(file); }

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

 

arduino

复制代码

public File getCanonicalFile() throws IOException { //好吧url的处理来到getCanonicalPath方法 String canonPath = getCanonicalPath(); return new File(canonPath, fs.prefixLength(canonPath)); }

 

arduino

复制代码

public String getCanonicalPath() throws IOException { //fs.resolve(this)这是重点关注对象 return fs.canonicalize(fs.resolve(this)); }

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

 

scss

复制代码

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()的实现吧

 

typescript

复制代码

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

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

作者:山城小辣椒
链接:https://juejin.cn/post/7239953755897823289
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值