This is the 7th day of my participation in the August Text Challenge.More challenges in August

We learned about class loading, we learned about parent delegate logic, and we wrote about how to define your own loader, but we didn’t write about how to break the parent delegate mechanism.

Negligence negligence.

Let’s start by writing a class loader

** @author xuxiaobai */ public MyClassLoader extends ClassLoader {private MyClassLoader extends ClassLoader {private MyClassLoader extends ClassLoader String classPath; public MyClassLoader(String classPath) { this.classPath = classPatetName()); } /** * this code, which I pulled directly from the ClassLoader, is annotated with some code. * First look for the class in the loaded region, If not, go to classPath and find * @param name * @Param resolve * @return * @throws ClassNotFoundException */ @Override public Class<? > loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already 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) { // // ClassNotFoundException thrown if class not found // // from the non-null parent class loader // } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } // } if (resolve) { resolveClass(c); } return c; Throws throws ClassNotFoundException */ Override protected Class<? > findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); Return defineClass(name, data, 0, data.length); return defineClass(name, data, 0, data.length); } catch (IOException e) { e.printStackTrace(); } return super.findClass(name); } /** * Import file data from disk ** @param name Class name * @return class file data * @throws IOException */ private byte[] loadByte(String name) throws IOException { name = name.replaceAll("\.", "/"); Class File classFile = new File(classPath + "/" + name + ".class"); FileInputStream fileInputStream = new FileInputStream(classFile); byte[] data = new byte[fileInputStream.available()]; fileInputStream.read(data); fileInputStream.close(); return data; }}Copy the code

As you can see, I skipped the method of calling the parent loader to load the class, and skipped the loading method of starting the loader, and loaded it directly myself. When it loads, it loads in its own classPath directory.

Let’s write another String class

We all know that parental delegation prevents core classes from being broken, but today we’re going to do the opposite and break the core class, String! Get over here!

We first need to create a String class using IDEA

And I’m going to write it. I’m not going to write any code here, right

package test.entity; /** * Created on 2021/8/30. * * @author xuxiaoba */ public class String { static { System.out.println("-- I'm a custom String--"); }}Copy the code

I was gonna use this little hammerTo edit our String class.

D: SRC \main\ Java \test\entity “; D: SRC \main\ Java \test\entity “;

As long as there are no errors.

Load the String class

Add a main method to the MyClassLoader class, which I won’t duplicate here.

public static void main(String[] args) throws ClassNotFoundException { MyClassLoader myClassLoader = new MyClassLoader("D:/src/main/java"); Class<? > clazz = myClassLoader.loadClass("test.entity.String"); System.out.println(clazz.getName()); }Copy the code

run

Bugs come out of the blue.

It is looking for the Object class, how to find my DRIVE D.

Is this what happens when you break parental delegation? Whatever it is, try to figure it out first.

Loading a class triggers the parent’s init method, which triggers the parent’s loading. In other words, I broke the parent delegate, so the JVM used our custom class loader to load the class.

Here, we’ll add a class Object to the “D: / SRC/main/Java/Java/lang” in a try.

For Java Object, you need to go to the jre lib package, find rt.jar, and unzip it to find object. class.

Let’s run again!

Because we inherit the ClassLoader, the ClassLoader restricts us from loading classes in the java.lang package. It’s a long way from breaking Java’s core classes.

Overall, we’ve broken the parent delegate mechanism, so let’s write a simple class to check.

The last

package test.entity; /** * Created on 2021/8/30. * * @author xuxiaobai */ public class A { static { System.out.println("--A--"); }}Copy the code

You can use the IDEA hammer to compile this class. After compiling, go to target/classes to find your own class. Sometimes the class will not compile, delete target and compile again. Then copy the.class file to “D: SRC \main\ Java \test\entity” and delete the class in IDEA.

Modify the main method of MyClassLoader.

On running, I will quote Prohibited package name: Java. Lang, it seems that we need to modify the code, though not loading String class, but it will pass our class loader loaded Object class.

The parent delegate mechanism will only be broken when classes under the test.entity package are loaded.

** @author xuxiaobai */ public MyClassLoader extends ClassLoader {private MyClassLoader extends ClassLoader {private MyClassLoader extends ClassLoader String classPath; public MyClassLoader(String classPath) { this.classPath = classPath; } public static void main(String[] args) throws ClassNotFoundException { MyClassLoader myClassLoader = new MyClassLoader("D:/src/main/java"); Class<? > clazz = myClassLoader.loadClass("test.entity.A"); System.out.println(clazz.getName()); } /** * this code, which I pulled directly from the ClassLoader, is annotated with some code. * First look for the class in the loaded region, If not, go to classPath and find * * @param name * @Param resolve * @return * @throws ClassNotFoundException */ @Override public Class<? > loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<? > c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); If (name.startswith ("test.entity")) {// Only classes starting with test.entity break the parent delegate mechanism c = findClass(name); } else { c = this.getParent().loadClass(name); } // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); // this is the defining class loader; record the stats PerfCounter.getParentDelegationTime().addTime(t1 - t0); PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); PerfCounter.getFindClasses().increment(); if (resolve) { resolveClass(c); } } return c; Throws throws ClassNotFoundException */ @override protected Class<? > findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); Return defineClass(name, data, 0, data.length); return defineClass(name, data, 0, data.length); } catch (IOException e) { e.printStackTrace(); } return super.findClass(name); } /** * Import file data from disk ** @param name Class name * @return class file data * @throws IOException */ private byte[] loadByte(String name) throws IOException { name = name.replaceAll("\.", "/"); Class File classFile = new File(classPath + "/" + name + ".class"); FileInputStream fileInputStream = new FileInputStream(classFile); byte[] data = new byte[fileInputStream.available()]; fileInputStream.read(data); fileInputStream.close(); return data; }}Copy the code

Last run!

Here is a small problem, today I wrote for two hours, a little tired, welcome everyone to make up