ResouceUtils. getFile () cannot obtain the source code Summary of Chinese source files in Jar,
Spring provides a tool class that can load files under classpath. In general, there is no problem, however, when it is used as a tool in the common jar package to load files in the jar package, an error is reported that the file cannot be found.
Click to see the source code of this tool class 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); } }
After reading the code structure, the logic is simple and clear, and there may be two problems: marked red. here, my first impression is that the class loader did not load resources. debug cl. the Class Loader used for getResource (path) is
WebAppClassLoader: I want to take a look at the internal implementation, but I won't go in here. Then Baidu finds that this is Jetty's own ClassLoader, intercepting some key loading source code:
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); } } } }
The above section adds the jar and zip path to some source code in the class loader path. Continue to debug to get
URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
The above url result:
Actually, the file path to be loaded is obtained. Because the protocol field in the jar package is identified as jar. it does not appear that the classloader causes file loading failure. so proceed to debug and look at the source code of 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()); } }
This is a bit speechless. The red text above actually determines whether the resource path protocol is file. Because in the jar package, the Protocol is jar, therefore, an exception not found in the file is directly thrown here,
I suddenly felt so stupid. After debugging for so long, I had to handle the class loading process again. In fact, the problem was a very simple problem, ResouceUtils. getFile () is a dedicated resource used to load non-compressed and Jar package file types, so it does not
To load the files in Jar, you only need to load the files in Jar by reading the files in jar, such as xx. class. getClassLoader (). getResouceAsStream () is a stream-based file reading method.