ResouceUtils.getFile()取不到Jar中資源檔源碼小結,

來源:互聯網
上載者:User

ResouceUtils.getFile()取不到Jar中資源檔源碼小結,

Spring提供了一個工具類可以載入classpath下的檔案,一般情況下無任何問題,但是當它作為公用的jar包中的工具來載入jar包中的檔案時則報出找不到檔案的錯誤.

點開看了一下這個工具類ResouceUtils.getFile()方法的源碼:

public static File getFile(String resourceLocation) throws FileNotFoundException {        Assert.notNull(resourceLocation, "Resource location must not be null");        if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {            String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length());            String description = "class path resource [" + path + "]";            ClassLoader cl = ClassUtils.getDefaultClassLoader();            URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));            if (url == null) {                throw new FileNotFoundException(description +                        " cannot be resolved to absolute file path because it does not exist");            }            return getFile(url, description);        }        try {            // try URL            return getFile(new URL(resourceLocation));        }        catch (MalformedURLException ex) {            // no URL -> treat as file path            return new File(resourceLocation);        }    }

看了一下代碼結構簡單邏輯清晰,可能有問題的也就是標紅的2處.這裡我第一印象是類載入器載入資源的時候沒載入到.Debug了一下cl.getResource(path)用的類載入器是

WebAppClassLoader,想看一下內部實現,但是到這裡就跟不進去了,然後百度了一下發現這個是Jetty實現的自己的ClassLoader,截取部分關鍵的載入源碼:

public void addJars(Resource lib)  {      if (lib.exists() && lib.isDirectory())      {          String[] files=lib.list();        for (int f=0;files!=null && f<files.length;f++)  {              try {                  Resource fn=lib.addPath(files[f]);                String fnlc=fn.getName().toLowerCase();                  if (fnlc.endsWith(".jar") || fnlc.endsWith(".zip"))  {                      String jar=fn.toString();                        jar=StringUtil.replace(jar, ",", "%2C");                      jar=StringUtil.replace(jar, ";", "%3B");                      addClassPath(jar);                  }              }  catch (Exception ex) {                  Log.warn(Log.EXCEPTION,ex);              }          }      }  } 

上面這塊是把jar和zip的path加到類載入器路徑中的部分源碼.繼續debug得到

URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));

上面的url結果:

 

實際上取到了要載入的檔案路徑,由於在jar包中,協議欄位被標識為jar.到這裡看來並非類載入器導致的負載檔案失敗.那隻好繼續debug往下看getFile()的源碼:

public static File getFile(URL resourceUrl, String description) throws FileNotFoundException {        Assert.notNull(resourceUrl, "Resource URL must not be null");        if (!URL_PROTOCOL_FILE.equals(resourceUrl.getProtocol())) {  //URL_PROTOCOL_FILE="file"            throw new FileNotFoundException(                    description + " cannot be resolved to absolute file path " +                    "because it does not reside in the file system: " + resourceUrl);        }        try {            return new File(toURI(resourceUrl).getSchemeSpecificPart());        }        catch (URISyntaxException ex) {            // Fallback for URLs that are not valid URIs (should hardly ever happen).            return new File(resourceUrl.getFile());        }    }

看到這裡有點無語了,上面紅色字型的部分實際判斷資源路徑的協議是否為file,由於在jar包中,協議是jar,故到此處直接拋出檔案未找到的異常,

頓時覺得自己好傻,debug這麼久,又理了一遍類載入的過程,其實問題是很簡單的一個問題,ResouceUtils.getFile()是專門用來載入非壓縮和Jar包檔案類型的資源,所以它根本不會

去嘗試載入Jar中的檔案,要想載入Jar中的檔案,只要用可以讀取jar中檔案的方式載入即可,比如 xx.class.getClassLoader().getResouceAsStream()這種以流的形式讀取檔案的方式.

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.