How to achieve custom ClassLoader

zhaozj2021-02-12  144

Author: Kert This article taken from: open systems world - SEOUL September 23, 2002

ClassLoader, as the name suggests is used to load Class, that is, load the Java class. ClassLoader reads an array of bytes and returns a Class instance that can be identified inside the JVM after processing. Java virtual machines use a complex but effective way to perform this vital process, and provide many flexible ways to expand this mechanism.

Why use custom ClassLoader

Many times people choose to use custom ClassLoaders without using the system's ClassLoader. The reason for this is that when compiling, it is impossible to predict the runtime, especially in some appserver, such as Tomcat, Avalon-Phonix, JBoss, or programs, providing some plugin (PLUG-IN) feature, let Users can add their own features in the case of only program binary code, such as Ant, Jxta-shell, etc.

ClassLoader internal structure

Usually customized a ClassLoader is very simple, usually only a few steps can be done.

The Java specification requires that all user-defined ClassLoaders must inherit from the abstract class "java.lang.classloader" class. Let's take a look at the internal implementation of this class to help us better understand the relevant content.

1: protected synchronized class loadclass (String name, Boolean 2: Resolve) throws classnotfoundexception {3: // First, check this class has been loaded. 4: Class C = FindloadedClass (Name); 5: IF (c == null) {6: try {7: if (parent! = Null) {8: c = parent.loadclass (name, false); 9:} Else {10: c = findbootstrapClass (name); 11:} 12:} catch (classnotfoundexception e) {13: // If there is still not found, then call FindClass to find this class. 14: c = findclass (name); / / SARSOR's NOTE: FINDCLASS () May Throw

// ClassNotFoundException why not try-catch block here15:} 16:} 17: if (resolve) {18: resolveclass (c); 19:} 20: Return C;

Usually we use ClassLoader.LoadClass (String Name): Class obtains a corresponding Class instance according to the specified class name. From the Java source code we can see that the default ClassLoader has made the following work:

1. Call FindloadedClass (String): Class checks if this Class has been loaded. Since the JVM specification specifies that the ClassLoader can keep it loaded in the ClassLoad, so if a Class has been loaded, it can be obtained directly from the cache.

2. Calling its parent class loadClass () method, if its parent class is empty, use the ClassLoad of ClassLoad inside the JVM to load this Class. At Chapter 10 We can see using a native method to call this Bootstrap ClassLoader. 3. If the above two steps are not found, call the FindClass (String): Class method to find and load this class.

So we only need to overwrite this FindClass (String): Class method can reach the requirements of the ClassLoader.

1: public class AnotherClassLoader extends ClassLoader {2: private String baseDir; private static final Logger LOG = 3: Logger.getLogger (AnotherClassLoader.class); 4: public AnotherClassLoader (ClassLoader parent, 5: String baseDir) {6: super (parent 7: this.basedir = basedir; 8:} 9: protected coplass findclass (string name) 10: throws classnotfoundexception {11: log.debug ("FindClass" name); 12: Byte [] Bytes = loadingClassbytes (Name ); 11: Class theclass = defineclass (name, bytes, 0, 14: bytes.length); 15: if (theclass == null) 16: throw new classformaterror (); 17: return theclass; 18:} 19: Private byte [] loadClassBytes (String className) throws20: ClassNotFoundException {21: try {22: String classFile = getClassFile (className); 23: FileInputStream fis = new FileInputStream (classFile); 24: FileChannel fileC = fis.getChannel (); 25: ByteaRrayoutputstream baos = new26: ByteArrayoutputStream (); 27: WritableBytechannel outc = channels.newchannel (baos); 28: Bytebuffer buffer = bytebuffer.allocate Direct (1024); 29: While (true) {30: int i = filec.read (buffer); 31: if (i = = 0 || i == -1) {32: Break; 33:} 34: buffer.flip (); 35: Outc.write (buffer); 36: buffer.clear (); 37:} 38: FIS. close (); 39: return baos.toByteArray (); 40:} catch (IOException fnfe) {41: throw new ClassNotFoundException (className); 42:} 43:} 44: private String getClassFile (String name) {45: StringBuffer SB = new stringbuffer (basedir); 46: name = name.replace ('.'

, File.seParetor char) ".class"; 47: sb.append (file.seParator Name); 48: return sb.toString (); 49:} 50:} is very simple code, key places Just 13 lines. We call the DefineClass method that converts the binary array obtained from the file to the corresponding Class instance. DefineClass is a native method that identifies the Class file format, analysis, analysis, reading the corresponding data structure, and generates a Class instance. We only found Class published in a directory, but how to get the corresponding resources? We sometimes use class.getResource () to get the corresponding resource file. If only the above ClassLoader is not found, the corresponding return value is NULL.

Similarly, let's take a look at the structure inside the original Class class.

1: public java.net.URL getResource (String name) {2: name = resolvename (name); 3: ClassLoader Cl = getClassLoader (); 4: if (cl == null) {5: return (name) {5: return classloader.getsystemResource (Name ); 6:} 7: return cl.getResource (name); 8:}

It turns out that the system uses the ClassLoader loaded this class to get resources. Then let's take a look at the implementation of the classloader.getresource (string) method:

1: Public url getresource (string name) {2: URL URL; 3: IF (Parent! = Null) {4: URL = Parent.getResource (Name); 5:} else {6: URL = getBootstrapResource (name); 7:} 8: if (URL == NULL) {9: URL = FindResource (Name); 10:} 11: Return URL; 12:}

Also in line 9, JVM will finally call a FindResource method to get the URL of the resource. Therefore, just inherited the FindResource (String) method as a FindClass method.

Add the following code in AnotherClassLoader:

1: Protected Url FindResource (String Name) {2: Log.debug ("FindResource" Name); 3: Try {4: URL URL = Super.FindResource (name); 5: IF (URL! = NULL) 6: Return URL; 7: URL = New URL ("File: ///" ConverName (Name)); 8: // Simplified Processing, all resources get 9: Return URLs from the file system; 10:} catch (Malformedurlexception MUE ) {11: log.error ("FindResource", MUE; 12: Return NULL; 13:} 14:} 15: Private string convername (string name) {16: stringbuffer sb = new stringbuffer (basedir); 17: Name = Name.Replace ('.', file.separatorchar); 18: sb.append (file.seParator Name); 19: return sb.toString (); 20:} Ok, here is a simple, customized ClassLoader is also done, and you can add other seasonings (such as security checks, modifying Class files, etc.) to meet your own taste.

ClassLoader supplementary instructions

1. Two ClassLoader defined in the Java specification, a BootstrapClassLoader, another becoming UserDefined ClassLoader. BootstrapClassLoader is part of the JVM, users are not changeable, which is mainly responsible for loading Class in JavaApi. UserDefinedClassLoader is user contact, including a SystemClassLoader and user-defined ClassLoader used to load Class_Path definitions.

2. This code uses the method under the java.nio packet in Java 1.4.

3. Each Class can get the ClassLoader loaded by classloadClassLoader (): ClassLoader method. However, for some JVM (including Sun's implementation) implementation, the GetClassLoader () method in the JavaApi returns NULL (see JavaDoc). (SARSOR Note: I have made a number of modifications, correct several obvious mistakes in the article, if I changed wrong, I am very sorry.

转载请注明原文地址:https://www.9cbs.com/read-7130.html

New Post(0)