Recently, I encountered the need to read the configuration file in my work. My first idea was to put the file in the resources directory of the project,
Then use:
String fileName = "config/zh.md" String path = this.getClass().getResource("/").getPath() + fileName; System.out.println(path);// D:/example/exam01/target/classes/config/zh.md
Everything is normal when developing and debugging in IDE tools, but java io. FileNotFoundException
java.io.FileNotFoundException: file:/usr/local/exam01-1.0-SNAPSHOT.jar!/BOOT-INF/classes!/config/zh.md (No such file or directory)
The error message is obvious because the file doesn't exist, but it can run normally in the IDE. Why can't it be put into a jar package on the server?
Carefully check the error path and find that there is no such path on the disk because the path is from/ exam01-1.0-SNAPSHOT.jar/... At first, the following file paths are all typed into the Jar package, and the disk is not followed/ BOOT-INF/classes!/config/zh.md directory;
The files in the Jar package have no actual path on the disk, so you can use this getClass().. Getresource() cannot get the file.
Solution 1
Directly upload the required files to the folder specified by the server. If the file path is written to death, it is too low and does not conform to the coding specification. Moreover, there are various hidden dangers. For example, different environments are published to different servers, one server is developed, one server is tested, and one server is produced. Each server must upload a copy; If you delete the file by mistake or forget to migrate the project, it will be troublesome;
Solution 2
You can use this getClass().. Getresourceasstream ("/config/zh.md") can get the file stream normally.
xxx.class.getResource("") and xxx class. getClassLoader(). getResource(“”)
The above problems have been solved. Let's take a look at xxx class. Getresource ("") and xxx class. getClassLoader(). The difference between getresource ("");
1. Actually, class getResource("/") == class. getClassLoader(). getResource("");
Class.getResource and classloader The essence of getresource is the same. Both use classloader Getresource loads the of the resource.
For class getResource:
Get the path of the file first. If it does not start with '/', the default is to get resources from the package where this class is located; When path begins with '/', resources are obtained from the ClassPath root of the project.
For classloader getResource:
Similarly, first obtain the path of the file. When the path does not start with '/', first load it through the parent delegation mechanism in the form of level by level upward delegation. Finally, it is found that the parent has not been loaded into the file. Finally, load the resource file under the classpath root through the current class.
For getResource("/"), '/' represents the loading range in Boot ClassLoader. Because this classloader is implemented in C++, the loading range is null.
2. The above two methods return java net. URL object. If you need to get the corresponding String type, you can use the following methods:
xxx.class.getResource("").getPath(); xxx.class.getResource("").getFile();
Or through InputStream input = getclass() getClassLoader(). getResourceAsStream("config\config.properties"); Obtain IO stream;
3. ClassLoader
We all know that Java files are run. The first step is to compile them into class files through the javac compiler; Step 2: the JVM runs the class file to realize cross platform.
The first step of the JVM virtual machine must be to load the class file. Therefore, the class loader implements:
Get the binary byte stream describing a class through the fully qualified name of the class
Class loaders have several important features:
- Each class loader has its own predefined search scope for loading class files;
- Each class and the class loader that loads it jointly determine the uniqueness of the class, that is, if a class file is loaded into the JVM by different class loaders, then the two classes are different classes, although they all come from the same class file;
3.1 parental delegation model
- All class loaders have a hierarchical structure. Each class loader has a parent class loader (implemented through composition, not inheritance), except for the Bootstrap ClassLoader
- When a class loader receives a class loading request, it first delegates the request to its parent loader to load, so each class loading request will eventually be passed to the top-level startup class loader. If the parent loader cannot load, the child class loader will try to load it by itself;
Three features of the class loader are realized through the parental delegation model:
delegation: the child class loader is delegated to the parent class loader for loading;
visibility: the child class loader can access the classes loaded by the parent class loader, while the parent class cannot access the classes loaded by the child class loader;
uniqueness: each class can be loaded only once. For example, the Object class is loaded by the Bootstrap ClassLoader. Because of the two parent delegation model, all Object class loading requests are delegated to the Bootstrap ClassLoader, so it can be loaded only once.
3.2 class loader in Java
From the perspective of JVM virtual machines, there are only two different class loaders:
- The Bootstrap ClassLoader is a part of the virtual machine itself;
- All other class loaders, independent of the virtual machine, inherit from the abstract class java lang.ClassLoader
Most Java applications will use the class loader provided by the system in the following 3:
- Boot class loader (Bootstrap/Primordial/NULL ClassLoader): the top-level class loader without a parent class loader. It is responsible for loading the in the /lib directory or in the path specified by the -Xbootclasspath parameter,
And the class libraries recognized by the JVM (only recognized by the file name, such as rt.jar, and the class libraries whose names do not match will not be loaded even if they are placed in the lib directory) are loaded into the virtual machine memory. All classes loaded by the Bootstrap classloader,
Its class The getclassloader method returns null, so it is also called NULL ClassLoader.
- Extension CLassLoader: by sun misc. The launcher$extclassloader implementation is responsible for loading in the /lib/ext directory or by java All class libraries under the directory specified by the ext.dirs system variable;
- Application/System ClassLoader: by sun misc. Launcher$appclassloader implementation. It is classloader The default return value of the getsystemclassloader () method,
So it is also called System ClassLoader. It is responsible for loading the class library specified in the classpath. If the application has not customized its own class loader, it is generally the default class loader in the program.
The following is the class loader hierarchy diagram in the Java program:
ClassPathResource load resource file usage - get configuration file path
ClassPathResource resolution
Take a look at Demo:
@Test public void test() throws IOException { Resource res = new ClassPathResource("applicationContext.xml"); InputStream input = res.getInputStream(); Assert.assertNotNull(input); }
Internal source code:
public ClassPathResource(String path) { this(path, (ClassLoader) null); } public ClassPathResource(String path, ClassLoader classLoader) { Assert.notNull(path, "Path must not be null"); String pathToUse = StringUtils.cleanPath(path); if (pathToUse.startsWith("/")) { pathToUse = pathToUse.substring(1); } this.path = pathToUse; this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); } public ClassPathResource(String path, Class<?> clazz) { Assert.notNull(path, "Path must not be null"); this.path = StringUtils.cleanPath(path); this.clazz = clazz; }
Get resource content:
@Override public InputStream getInputStream() throws IOException { InputStream is; if (this.clazz != null) { is = this.clazz.getResourceAsStream(this.path); } else if (this.classLoader != null) { is = this.classLoader.getResourceAsStream(this.path); } else { is = ClassLoader.getSystemResourceAsStream(this.path); } if (is == null) { throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist"); } return is; }
So there are two ways for a class to obtain resources
Class Access and ClassLoader obtain.
Demo and difference between the two methods:
Demo:
@Test public void test1() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // ClassLoader.getResource("") gets the root path of the classpath System.out.println("a--- " + classLoader.getResource("").getPath()); // new ClassPathResource() obtained an empty path System.out.println("b--- " + new ClassPathResource("/").getPath()); System.out.println("b-1--- " + new ClassPathResource("").getPath()); // Class.getResource("") gets the relative path relative to the current class System.out.println("c--- " + this.getClass().getResource("").getPath()); // Class.getResource("/") gets the root path of the classpath System.out.println("d--- " + this.getClass().getResource("/").getPath()); }
Output:
a--- /E:/xie-my-install/devolop/eideaworkspace/ideatest/target/classes/ b--- b-1--- c--- /E:/xie-my-install/devolop/eideaworkspace/ideatest/target/classes/com/xie/util/ d--- /E:/xie-my-install/devolop/eideaworkspace/ideatest/target/classes/
difference
- Class.getResource("") gets the relative path relative to the current class
- Class.getResource("/") gets the root path of the classpath
- ClassLoader.getResource("") gets the root path of the classpath
- new ClassPathResource(“”). Empty path. If no relative class name is specified, the class will search for a resource from the root path of the class. If a relative class name is specified, the class will search for a resource according to the relative path of the specified class.
(if it is typed as an executable jar package, you can use this method to create a file path under the same level directory of the jar: new classpathresource ("") getPath() + "/" + UUidUtil. getStrUUID() + ".jpg";) This may not have been thoroughly studied - When creating a ClassPathResource object, we can specify whether to obtain the file by the relative path of Class or by ClassLoader.