Java class loader (2) -- custom Class Loader
You can customize your ClassLoader to implement the following applications:
Find the custom class file in the custom path. Maybe the class file we need is not always under the configured Classpath, so we must find this class, in this case, we need to implement a ClassLoader by ourselves. Ensure security: Java itself is easily decompiled, and special processing is performed on the classes we want to load, such as ensuring the security of classes transmitted over the network, classes can be encrypted before transmission. Before encryption to JVM, You need to decrypt the class bytecode. This process can be implemented in the Custom ClassLoader. Hot deployment of implementation classes: You can define the implementation mechanism of classes. If you can check whether the loaded class files have been modified, You can reload the class.
The findClass () function is to locate the class file and load the bytecode into the memory. The custom ClassLoader generally overwrites the modification method to use different loading paths, and then calls defineClass () to parse the bytecode.
The defineClass () method is used to parse byte streams into Class objects that can be recognized by JVM. With this method, we can not only instantiate objects through class files, but also instantiate objects in other ways. For example, we receive a class bytecode through the network, this byte code stream is used to create Class objects to instantiate objects.
The custom loader can override the loadClass () method to define different loading mechanisms.
If the custom loader only overwrites findClass (), but does not overwrites loadClass (that is, the loading rules are the same, but the loading paths are different), call getClass (). getClassLoader () still returns AppClassLoader! Because the real load class is still AppClassLoader.
Load the class file in the custom path
The following example shows how to load a class file in the specified path ("D:/workspace_jee/JavaTest/src.
package classloader;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;public class PathClassLoader extends ClassLoader{ private String classPath; public PathClassLoader(String classPath) { this.classPath = classPath; } @Override protected Class
findClass(String name) throws ClassNotFoundException { byte[] classData = getData(name); if (classData == null) { throw new ClassNotFoundException(); } else { return defineClass(name, classData, 0, classData.length); } } private byte[] getData(String className) { String path = classPath + File.separatorChar+className.replace('.', File.separatorChar)+".class"; try { InputStream is = new FileInputStream(path); ByteArrayOutputStream stream = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; int num = 0; while((num = is.read(buffer))!=-1) { stream.write(buffer,0,num); } return stream.toByteArray(); } catch(IOException e) { e.printStackTrace(); } return null; } public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException { ClassLoader pcl = new PathClassLoader("D:/workspace_jee/JavaTest/src/"); Class c = pcl.loadClass("classloader.SingleClass"); System.out.println(c.newInstance()); }}
Output result: [email protected]
Load a class file in custom format
If we download the bytecode of a class file from the network, but to ensure security, we simply encrypt the bytecode before transmission, and then transmit it over the network. After the client receives the bytecode of this class, it must be decrypted to restore it to the original class format. Then, it creates an instance of this class through the defineClass () method of ClassLoader, finally, load the class.
For example, in the above Code, after obtaining the bytecode (byte [] classData = getData (name);), you can use a code similar to the following:
Private byte [] deCode (byte [] src) {byte [] decode = null; // do something niubility! Return decode ;}
Decodes the required bytecode.
Hot deployment of implementation classes
By default, the JVM cannot hot deploy classes, because the findLoadedClass () is called when a class is loaded. If the class has been loaded, it will not be loaded again.
The JVM determines whether a class is loaded with two conditions: whether the complete class name is the same, and whether the ClasssLoader is the same
To achieve hot deployment, you only need to use different instances of ClassLoader for loading.
If you use the same ClassLoader instance to load the same class, a LinkageError will be thrown.
Jsp is an example of hot deployment.
As follows:
package classloader;import java.io.ByteArrayOutputStream;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;public class ClassReloader extends ClassLoader{ private String classPath; String classname = "classloader.SingleClass"; public ClassReloader(String classpath) { this.classPath = classpath; } protected Class
findClass(String name) throws ClassNotFoundException{ byte [] classData = getData(name); if(classData == null) { throw new ClassNotFoundException(); } else { return defineClass(classname,classData,0,classData.length); } } private byte[] getData(String className) { String path = classPath+className; try { InputStream is = new FileInputStream(path); ByteArrayOutputStream stream = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; int num = 0; while((num = is.read(buffer))!=-1) { stream.write(buffer,0,num); } return stream.toByteArray(); } catch(IOException e) { e.printStackTrace(); } return null; } public static void main(String[] args) { try { String path = "D:/workspace_jee/JavaTest/src/classloader/"; ClassReloader reloader = new ClassReloader(path); Class r = reloader.findClass("SingleClass.class"); System.out.println(r.newInstance());// ClassReloader reloader2 = new ClassReloader(path); Class r2 = reloader.findClass("SingleClass.class"); System.out.println(r2.newInstance()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } }}
The running result of this Code is:
java.lang.LinkageError: loader (instance of classloader/ClassReloader): attempted duplicate class definition for name: "classloader/SingleClass" at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(Unknown Source) at java.lang.ClassLoader.defineClass(Unknown Source) at classloader.ClassReloader.findClass(ClassReloader.java:26) at classloader.ClassReloader.main(ClassReloader.java:62)
Compare whether the two classes are "equal" and make sense only when the two classes are loaded by the same Class loader. Otherwise, even if the two classes are from the same Class file, loaded by the same virtual machine, as long as their class loaders are different, the two classes will be not equal.