Writing and testing custom class loaders

Keywords: Java jvm

1, Overview

1. The user-defined ClassLoader must inherit ClassLoader

2. loadClass method and findClass method

The findClass() method is generally overridden, which loads the class into the jvm itself. The loadClass() method does not need to be overridden. It is a complete process of calling the parent delegation mechanism.

3. defineClass method

Pass in a byte [] array and return a Class object.

2, Key points

1. Write a program to call the class loader to load the class. The reference variable cannot be defined with the class name in the source program, because the compiler cannot recognize the class. In addition to the ClassLoader.load method, you can also use the context class loader or system class loader that sets the thread, and then use Class.forName
2. Replace the class file in the CLASSPATH environment with the encrypted class file, and then perform the previous operation. The error indicates that the AppClassLoader class loader failed to load

3. Delete the class file in the CLASSPATH environment, and then perform the previous operation

3, Code description

    1,MyClassLoader.java

package staticimport.classloader.custom;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/***
 * 
 * Write and test your own decryption class loader
 * 
 * 
 * @author Liu
 *
 */
public class MyClassLoader extends ClassLoader {
	private String classPath;

	public MyClassLoader(String classPath) {
		super();
		this.classPath = classPath;
	}

	public MyClassLoader() {
		super();
	}

	public MyClassLoader(ClassLoader parent) {
		super(parent);
	}

	@SuppressWarnings("deprecation")
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		try {
//			String srcPath = classPath + "\\" + name + ".class";
			String srcPath = classPath + "\\" + name.substring(name.lastIndexOf(".") + 1) + ".class";
			InputStream is = new FileInputStream(srcPath);

			ByteArrayOutputStream os = new ByteArrayOutputStream();
			cypher(is, os);
			
			is.close();

			byte[] bytes = os.toByteArray();
			os.close();

			// return defineClass(name, bytes, 0, bytes.length);
			return defineClass(bytes, 0, bytes.length);

		} catch (Exception e) {
			e.printStackTrace();
		}

		return super.findClass(name);
	}

	public static void main(String[] args) throws Exception {
		String srcPath = args[0];
		String destDir = args[1];

		String fileName = srcPath.substring(srcPath.lastIndexOf("\\") + 1);

		String destPath = destDir + "\\" + fileName;

		InputStream is = new FileInputStream(srcPath);

		OutputStream os = new FileOutputStream(destPath);

		cypher(is, os);
		
		is.close();
		os.close();
	}

	// Byte encryption and decryption algorithm
	private static void cypher(InputStream is, OutputStream os) throws Exception {
		int b = -1;
		while ((b = is.read()) != -1) {
			os.write(b ^ 0xFFFF);
		}
	}
}

2. Calling code of main class

		Class clazz = new MyClassLoader("cllib").loadClass("staticimport.classloader.custom.ClassLoaderAttachment");
		//Reason for ClassLoaderAttachment inheriting Date type, skipping compiler check!
		Date date = (Date) clazz.newInstance();
		System.out.println(date);

Note:

To test the encryption algorithm, you need to configure the main() method of MyClassLoader.java to pass in parameters

Posted by turboprop on Mon, 27 Apr 2020 08:09:41 -0700