Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How does Java use classpath to get resources

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article introduces the knowledge of "how Java uses classpath to obtain resources". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Java can access resources in the following ways:

GetResource method of Class

GetResource method of ClassLoader

GetSystemResource static method of ClassLoader

In use, the Class can be obtained either by referring directly to the class property of the class, or by the getClass () method of the instance. There are many ways to obtain ClassLoader. The following are common:

Call the getClassLoader method of Class, such as getClass () .getClassLoader ()

Gets ClassLoader:Thread.currentThread (). GetContextClassLoader () by the current thread

Get system ClassLoader: ClassLoader.getSystemClassLoader ()

However, if you don't know much about Java's ClassLoader concept, it's best to avoid using it as much as possible.

The difference between Class.getResource and ClassLoader.getResource

Both methods accept a path expression in the form of a string, the name of the resource, and return the URL of the resource found. Both methods can be used to locate resources, and both are common in articles circulating on the Internet. In fact, Class's getResource method also calls ClassLoader's getResource method, but the two are very different. If you don't understand the difference between these two methods, it's easy to cause hidden trouble. Hidden dangers are often much more frightening than mistakes made at the time of writing, because it is normal in certain situations and is not easy to detect.

The biggest difference between the two is where to start looking for resources. ClassLoader does not care about the package name path of the current class; it always locates resources based on classpath. Unlike Class.getResource, if the resource name is an absolute path (starting with "/"), it removes the opening "/" and then calls the getResource method of ClassLoader to find the resource; if the resource name is a relative path, it looks for the resource under the current package path.

For example, suppose we have a class: test.App (package name test), and under the test package there is a js file named App.js with the same name as the class name. If you use ClassLoader to get the js file, you should write:

App.class.getClassLoader () .getResource (test/App.js)

If you use Class's getResource method, you can write it in two ways:

Use relative paths:

App.class.getResource ("App.js")

Use absolute paths:

App.class.getResource ("/ test/App.js")

From the above example, we can see the great difference between the two. Some people copy similar code from the network, see if it doesn't work correctly, and start trying to add "/" in front of the resource name, or remove the first "/". If the attempt is successful, it will be considered finished.

There are other differences between Class and ClassLoader's getResource method. For Class's getResource method, if you pass in a relative path, it will also try to convert the package name to the path name. Looking at the source code of the Class.getResource method, you can see that it first calls the resolveName method on the resource name, and then calls the getResource method of ClassLoader to complete the location of the resource.

Test code

As a demonstration, I wrote the following code to show the output of the getResource method of Class and ClassLoader:

/ * Copyright (c) 2014 Chen Zhiqiang. Released under the MIT license. * / package test;import java.net.URL;import java.util.Enumeration;/** * Tests for the use of {@ link Class#getResource (String)} and * {@ link ClassLoader#getResource (String)}. * * @ author Chen Zhiqiang * / public class ClassResourceTest {Class cls = ClassResourceTest.class; ClassLoader ldr = cls.getClassLoader (); / / Thread.currentThread () .getContextClassLoader () public static void println (Object s) {System.out.println (s);} void showResource (String name) {println ("# # Test resource for:" + name + "# #") Println (String.format ("ClassLoader#getResource ("% s ") =% s", name, ldr.getResource (name)); println (String.format ("Class#getResource ("% s ") =% s", name, cls.getResource (name));} public final void testForResource () throws Exception {showResource ("); showResource (" / "); showResource (cls.getSimpleName () +" .class ") String n = cls.getName (). Replace ('.','/') + ".class"; showResource (n); showResource ("/" + n); showResource ("java/lang/Object.class"); showResource ("/ class") } public static void main (String [] args) throws Exception {println ("java.class.path:" + System.getProperty ("java.class.path"); println ("user.dir:" + System.getProperty ("user.dir")); println (""); ClassResourceTest t = new ClassResourceTest (); t.testForResource ();}}

Compile the above code to see the output of different resource paths.

Changes after being packaged into Jar packages

Now, package the compiled result of the above code into a Jar file, suppose it is test.jar, then run the above code from this jar package, look at the output, and compare the changes with the above output:

Java-classpath test.jar test.ClassResourceTest

A few points worth noting:

Class.getResource ("") has some other output, which turns out to be a file:/some_path... filebank with some output path, which is file:/some_path... before it is packaged as jagged path.

Class.getResource ("/") is null, and before packaging, the output is the classpath of ClassResourceTest

ClassLoader.getResource ("") is null, and before packaging, the output is the classpath of ClassResourceTest

When calling the ClassLoader.getResource method, if the resource name is absolute path, whether packaged or not, the output is null, at least in my case.

Mistakes and traps

Use Class.getResource ("/") or ClassLoader.getResource ("") as the root of the classpath.

This is a common mistake and is widely circulated on the Internet. When they are packaged into Jar packages, the results change.

After you get the output of the getResource method, simply call getFile or getPath on the result and treat it as a file path.

Resources may be in the classpath in the form of files and directories, but they may also be packaged in Jar or Zip packages, and you can't assume that your code will not be packaged.

Pass the absolute path to the getResource method of ClassLoader.

Some people on the network say that for ClassLoader's getResource method, whether the resource name starts with "/" is the same. However, in my case, ClassLoader's getResource method does not accept an absolute path, and its output is null.

Correct use of getResource method

Avoid using Class.getResource ("/") or ClassLoader.getResource (""). You should pass in an exact resource name and calculate the output. For example, if you really want to get the starting point of the classpath from which the current class is executed, in the case of test.App mentioned earlier, you can call App.class.getResource (App.class.getSimpleName () + ".class"). If the result is not the URL of the jar protocol, it means that the class file is not packaged. Remove the "test/App.class" in the tail of the result, and you can get the starting point of the classpath of the test.App; if the result is the URL of the jar protocol, remove the "! / test/App.class" in the tail, and the previous "jar:", that is, the url of the jar file where the test.App is located.

If you want to locate resources in the same package as a class, try to use the getResource method of that class and use the relative path. As mentioned earlier, to get the App.js file in the same package as test.App.class, use App.class.getResource ("App.js"). Of course, there is no certainty. ClassLoader.getResource ("test/App.js") is fine, depending on what problem you are facing.

If you don't know much about ClassLoader, try to use Class's getResource method.

If you don't understand or can't determine the relative path to the Class.getResource method, use the top-level package path of the classpath as the reference starting point, and always pass it a path that starts with "/".

Don't assume that your debugging environment is the last running environment. Your code may not be packaged, or it may be packaged, you have to consider these situations, do not bury the hole.

GetResources: enumerating resources

Java's CLASSPATH is a list of paths, so it is possible for the same resource name to appear in multiple classpath. If you want to enumerate them, you can use ClassLoader's getResources method.

The following code enumerates all "META-INF/MANIFEST.MF", and you can observe which jar files contain the resource in the classpath:

Import java.net.URL;import java.util.Enumeration;public class Test {public static void main (String [] args) throws Exception {ClassLoader ldr = Test.class.getClassLoader (); System.out.println ("# # Test for getResources ('META-INF/MANIFEST.MF') # #"); Enumeration urls = ldr.getResources ("META-INF/MANIFEST.MF") While (urls.hasMoreElements ()) System.out.println (urls.nextElement ());}} instance

The following code demonstrates how to correctly get the classpath starting point of the code:

/ * Copyright (c) 2014 Chen Zhiqiang. Released under the MIT license. * / package test;import java.io.File;import java.net.MalformedURLException;import java.net.URL;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * demonstrates how to get the starting point of the current classpath * * @ author Chen Zhiqiang * / public class AppDirTest {Classcls = AppDirTest.class; URL codeLocation = getCodeLocation (); / * Get the code location. * * Return the classpath where the code run from. The return url will be: * file:/path/my-app/calsses/ or file:/path/my-app/my-app.jar * * @ return URL * / public URL getCodeLocation () {if (codeLocation! = null) return codeLocation / / Get code location using the CodeSource codeLocation = cls.getProtectionDomain (). GetCodeSource (). GetLocation (); if (codeLocation! = null) return codeLocation; / / If CodeSource didn't work, use {@ link} Class.getResource instead. URL r = cls.getResource (""); synchronized (r) {String s = r.toString (); Pattern jar_re = Pattern.compile ("jar:\ s? (. *)! /. *"); Matcher m = jar_re.matcher (s) If (m.find ()) {/ / the code is run from a jar file. S = m.group (1);} else {String p = cls.getPackage (). GetName (). Replace ('.','/'); s = s.substring (0, s.lastIndexOf (p)) } try {codeLocation = new URL (s);} catch (MalformedURLException e) {throw new RuntimeException (e);}} return codeLocation } / * Get the class path root where the program startup, if run in a jar, * return the jar file's parent path. * * @ return * / public String getAppDir () {File f = new File (getCodeLocation (). GetPath ()); return f.isFile ()? F.getParent (): f.getPath ();} public static void main (String [] args) {AppDirTest t = new AppDirTest (); System.out.println ("code location:" + t.getCodeLocation ()); System.out.println ("app dir:" + t.getAppDir ()) That's all for "how Java uses the classpath to get resources". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report