In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
In view of how to use the Class loading system ClassLoader in java, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.
ClassLoader plays a very important role in Java, its main work is in the loading stage of Class loading, and its main function is to obtain Class binary data stream from outside the system.
1. Get to know ClassLoader
ClassLoader is the core component of java. All Class is loaded by ClassLoader. ClassLoader is responsible for loading ClassLoader in the whole loading phase in various ways, which can only affect the loading of the class, but cannot change the connection and initialization behavior of the class through ClassLoader.
At the code level, ClassLoader is an abstract class that provides some important interfaces for customizing the loading process and method of Class. The main methods of ClassLoader are as follows:
Public Class loadClass (String name) throws ClassNotFoundException: given a class name, load a class and return the code for a Class instance of the class, or a ClassNotFoundException exception if the class is not found.
Protected final Class defineClass (byte [] b, int off, int len): defines a class based on a given byte stream b, and the off and len parameters represent the location and length of the actual Class information in the byte array, where the byte array b is obtained by ClassLoader from the outside. This is a protected method and can only be used in a custom ClassLoader subclass.
Protected Class findClass (String name) throws ClassNotFoundException: find a class, which is a protected method and an important system extension point when overloading ClassLoader. This method is called in loadClass () to customize the logic of the lookup class. If you do not need to modify the default mechanism of class loading, but just want to change the form of class loading, you can overload the method.
Protected final Class findLoadedClass (String name): this is also a protected method that looks for classes that have already been loaded. This method is the final method and cannot be modified.
In the structure of ClassLoader, there is another important field: parnet. It is also an instance of ClassLoader, and the ClassLoader represented by this field is called the parent of the ClassLoader. During class loading, ClassLoader may hand over some requests to its parents.
2. Classification of ClassLoader
In standard java programs, the java virtual machine creates three types of ClassLoader to serve the entire application. They are: Bootstrap ClassLoader (boot class loader), Extension ClassLoader (extended class loader) and App ClassLoader (application class loader, also known as system class loader). In addition, each application can have a custom ClassLoader to extend the ability of the java virtual machine to obtain Class data.
The ClassLoader hierarchy is shown in the following figure. When the system needs to use a class, it starts with the underlying class loader when determining whether the class has been loaded. When the system needs to load a class, it starts with the top-level class and tries down until it succeeds.
Startup class loader: it is implemented entirely in C language, and there is no corresponding object in java. It is responsible for loading the core classes of the system, such as the java class in rt.jar.
Extension class loader: used to load the java class in% JAVA_HOME%/lib/ext/*.jar.
Application class loader: used to load user classes, that is, classes of user programs.
Custom class loader: a class used to load some special ways, generally also the class of a user program.
The following code outputs the loaded classloader:
Public class Demo04 {public static void main (String [] args) {ClassLoader cl = Demo04.class.getClassLoader (); while (cl! = null) {System.out.println (cl.getClass (). GetName ()); cl = cl.getParent ();}
The code first takes the ClassLoader that loads the current class Demo04, then prints the current ClassLoader and gets its parents until the classloader tree is traversed. The running results are as follows:
Sun.misc.Launcher$AppClassLoadersun.misc.Launcher$ExtClassLoader
From this, we know that Demo03 is loaded by AppClasLoader (application class loader), and AppClassLoader's parents are ExtClassLoader (extended class loader). The boot class loader can no longer be obtained from ExtClassLoader because it is a system-level pure C language implementation. Therefore, any class loaded in the startup class loader cannot get its ClassLoader instance, such as:
String.class.getClassLoader ()
Because String belongs to the java core class and will be loaded by the startup class loader, the above code returns null.
3. ClassLoader's parental entrustment model
When the ClassLoader in the system works together, the parent delegation mode is used by default. When the class is loaded, the system will determine whether the current class has been loaded, and if it has been loaded, it will directly return the available class, otherwise it will attempt to load. When you try to load, the parents are asked to process it, and if the request fails, it loads itself.
The following code shows the detailed process of ClassLoader loading a class, which is implemented in ClassLoader.loadClass ():
Protected Class loadClass (String name, boolean resolve) throws ClassNotFoundException {synchronized (getClassLoadingLock (name)) {/ / check whether the class has been loaded Class c = findLoadedClass (name); if (c = = null) {long t0 = System.nanoTime () Try {if (parent! = null) {c = parent.loadClass (name, false);} else {c = findBootstrapClassOrNull (name) }} catch (ClassNotFoundException e) {/ / if the parents are not null / / if the parents do not load successfully Throw ClassNotFoundException} if (c = = null) {/ / if parents load unsuccessfully / / use findClass to find class long T1 = System.nanoTime () C = findClass (name); / / define a class loader to record data sun.misc.PerfCounter.getParentDelegationTime (). AddTime (T1-T0); sun.misc.PerfCounter.getFindClassTime (). AddElapsedTimeFrom (T1); sun.misc.PerfCounter.getFindClasses (). Increment () }} if (resolve) {resolveClass (c);} return c;}}
When determining whether the class is loaded, the application classloader determines up the parent path until the classloader is started. But the startup class loader does not ask further, and the delegate is one-way.
4. The disadvantages of the parental entrustment model
As you can see from the previous analysis, the delegate process to check whether the class has been loaded is one-way. Although the structure of this method is clear and the responsibility of using each ClassLoader is very clear, it brings a problem: the upper ClassLoader cannot access the classes loaded by the lower ClassLoader, as shown below:
In general, the class in the startup class loader is the system core class, including some important system interfaces, and the application class in the application class loader. According to this model, it is no problem for the application class to access the system class, but there will be a problem for the system class to access the application class. For example, an interface is provided in the system class that needs to be implemented in the application, and a factory method is bound to create an instance of the interface, and both the interface and the factory method are in the startup class loader. This leads to the problem that the factory method cannot create an application instance by the application class loader.
5. A supplement to the parental entrustment model
In the java platform, the interface that provides external services in the core class (rt.jar) and can be implemented by the application layer itself is called Service Provider Interface, that is, SPI.
Taking the XML file parsing function module in javax.xml.parsers as an example, this paper illustrates how to access the SPI interface instance implemented by the application class loader in the startup class loading.
Public static DocumentBuilderFactory newInstance () {return FactoryFinder.find (/ * The default property name according to the JAXP spec * / DocumentBuilderFactory.class, / / "javax.xml.parsers.DocumentBuilderFactory" / * The fallback implementation class name * / "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");}
The FactoryFinder.find () function attempts to load and return an instance of DocumentBuilderFactory. When this instance is in the application layer jar package, it looks for it using the following methods:
Object provider = findJarServiceProvider (factoryId)
FactoryId is the string javax.xml.parsers.DocumentBuilderFactory,findJarServiceProvider. The main content of the code is shown below (this code is not the source code in jdK. It has been deleted to demonstrate the main functions):
Private static Object findJarServiceProvider (String factoryId) throw ConfigurationError {String serviceId = "META-INF/services" + factoryId; InputStream is = null; ClassLoader cl = ss.getContextClassLoader (); InputStream is = ss.getResourceAsStream (cl, serviceId); BufferedReader rd = new BufferedReader (new InputStreamReader (is, "UTF-8")); String factoryClassName = rd.readLine (); return newInterface (factoryClassName, cl, false, useBSClsLoader);}
As can be seen from the above code, the system reads the factory class name by reading the class name file under the META-INF/services directory in the jar package, then generates the corresponding instance according to the class name, and passes the ClassLoader into the newInstance () method, which completes the instance loading and creation by this ClassLoader, rather than by the startup class loader where the code is located. This solves the problem that the startup class loader cannot access the class specified by factoryClassName.
In the above code, loading the factory class method is slightly tortuous. When we write the code, we know the package name of a class. The name of the class, which is usually done to generate the object of the class:
Class.forname ("package name. class name"), get the Class object.
After you get the Class object, call the Class.newInstance () method to generate an instance of the object.
However, in DocumentBuilderFactory, this doesn't work, mainly because Class.forName () can't get the classloader. Let's look at the source code of Class.forName ():
Public static Class forName (String className) throws ClassNotFoundException {Class caller = Reflection.getCallerClass (); return forName0 (className, true, ClassLoader.getClassLoader (caller), caller);}
As you can see from the above, in any class where Class.forName () is called, the class loader that loads that class is used for class loading, that is, DocumentBuilderFactory calls Class.forName (), and the class loader that loads DocumentBuilderFactory is used to load the package name. Class name, but the problem is that DocumentBuilderFactory is loaded by BootClassLoader, and the obtained class loader is null, which cannot load the package name. Class name.
6. Break through the parental model
Class loading in parent mode is the default behavior of the virtual machine, but it is not necessary, and this behavior can be modified by overloading ClassLoader. Here's how to break the default parenting pattern:
Package jvm.chapter10;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.nio.ByteBuffer;import java.nio.channels.Channels;import java.nio.channels.FileChannel;import java.nio.channels.WritableByteChannel;class MyClassLoader extends ClassLoader {private String fileName; public MyClassLoader (String fileName) {this.fileName = fileName;} @ Override protected Class loadClass (String name, boolean resolve) throws ClassNotFoundException {Class re = findClass (name) If (re! = null) {return re;} System.out.println ("load class" + name + "failed, parent load start"); return super.loadClass (name, resolve);} @ Override protected Class findClass (String className) throws ClassNotFoundException {Class clazz = this.findLoadedClass (className) If (null = = clazz) {try {String classFile = getClassFile (className); FileInputStream fis = new FileInputStream (classFile); FileChannel fileChannel = fis.getChannel (); ByteArrayOutputStream baos = new ByteArrayOutputStream (); WritableByteChannel outChannel = Channels.newChannel (baos); ByteBuffer buffer = ByteBuffer.allocateDirect (1024) While (true) {int I = fileChannel.read (buffer); if (I = = 0 | | I = =-1) {break;} buffer.flip (); outChannel.write (buffer); buffer.clear () } fis.close (); byte [] bytes = baos.toByteArray (); clazz = defineClass (className, bytes, 0, bytes.length);} catch (Exception e) {e.printStackTrace ();}} return clazz } private String getClassFile (String packageName) {return fileName + packageName.replaceAll ("\\.", File.separator) + ".class" }} / * {add a description here} * * @ author chengyan * @ date 2019-11-29 4:12 PM * / public class Demo05 {public static void main (String [] args) throws Exception {MyClassLoader myClassLoader = new MyClassLoader ("/ Users/chengyan/IdeaProjects/myproject/DataStructuresAndAlgorithms/out/production/DataStructuresAndAlgorithms/"); Class clz = myClassLoader.loadClass ("jvm.chapter10.Demo01") System.out.println (clz.getClassLoader (). GetClass (). GetName ()); System.out.println ("= class load tree="); ClassLoader cl = clz.getClassLoader (); while (cl! = null) {System.out.println (cl.getClass (). GetName ()); cl = cl.getParent ();}
The above code changes the default loading mode of delegated parents by customizing the ClassLoader overload loadClass () method. The running result is as follows:
Java.io.FileNotFoundException: / Users/chengyan/IdeaProjects/myproject/DataStructuresAndAlgorithms/out/production/DataStructuresAndAlgorithms/java/lang/Object.class (No such file or directory) at java.io.FileInputStream.open0 (Native Method) at java.io.FileInputStream.open (FileInputStream.java:195) at java.io.FileInputStream. (FileInputStream.java:138) at java.io.FileInputStream. (FileInputStream.java:93) at jvm.chapter10.MyClassLoader. FindClass (Demo05.java:36) at jvm.chapter10.MyClassLoader.loadClass (Demo05.java:22) at java.lang.ClassLoader.loadClass (ClassLoader.java:357) at java.lang.ClassLoader.defineClass1 (Native Method) at java.lang.ClassLoader.defineClass (ClassLoader.java:763) at java.lang.ClassLoader.defineClass (ClassLoader.java:642) at jvm.chapter10.MyClassLoader.findClass (Demo05.java:52) At jvm.chapter10.MyClassLoader.loadClass (Demo05.java:22) at java.lang.ClassLoader.loadClass (ClassLoader.java:357) at jvm.chapter10.Demo05.main (Demo05.java:76) load class java.lang.Object failed Parent load startjvm.chapter10.MyClassLoader=class load tree=jvm.chapter10.MyClassLoadersun.misc.Launcher$AppClassLoadersun.misc.Launcher$ExtClassLoader
As you can see, the program first attempts to load the Object class by MyClassLoader, but because there is no such information in the specified path, the load fails and an exception is thrown, but then the application class loader loads successfully. Then try to load the Demo01,Demo01 in the specified path, and load successfully. Print the ClassLoader loaded with Demo01, displayed as MyClassLoader, and print the ClassLoader hierarchy, followed by MyClassLoader,AppClassLoader,ExtClassLoader.
This is the answer to the question about how to use the Class loading system ClassLoader in java. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel for more related knowledge.
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.