git

Github.com/fw103699437… Java. Lang. String branch

preface

Old problem, also search a pile of answers to the net, for example, come casually

At first glance, this might seem like a good idea, but now that you’ve mastered custom classloaders and learned how to break parental delegation, there are two problems: 1. Why do you think I’m ApplicationClassLoader now? After all, many frameworks have custom classloaders 2: Why do you think I have to go parental delegate? If you doubt it, you’ll need proof to write a program that: 1: breaks parental delegation; 2: writes java.lang.String class code. See git

Take a look at some of the important parts

package java.lang;

public class String {
    private Integer a;

    public Integer getA(a) {
        return a;
    }

    public void setA(Integer a) {
        this.a = a; }}Copy the code
package org.wayne;

import org.wayne.util.ClassLoaderUtil;

import java.lang.reflect.Method;

public class RegisterDriverUtil {
    public static void register(String name){
        Class pluginClass = ClassLoaderUtil.getPluginClass(RegisterDriverUtil.class);
        try {
            Method method = pluginClass.getDeclaredMethod("register", String.class);
            method.setAccessible(true);
            method.invoke(pluginClass.newInstance(),name);
        } catch (Exception e) {
            throw newRuntimeException(e); }}}Copy the code
package org.wayne;

public class RegisterDriverUtil {
    public void register(String name) throws ClassNotFoundException { Class.forName(name); }}Copy the code
    public static void test8(a){
        EnvironmentUtil.setEnv(EnvEnum.A);
        RegisterDriverUtil.register("java.lang.String");
        EnvironmentUtil.clearEnv();
    }
Copy the code

Package, run under WSL, and the result is as follows

The java.lang.String class was loaded directly with the custom ClassLoader and did not delegate to the parent

why

Regardless of the custom classloader, the defineClass method that is called ends up loading byte[], commented below

    protected finalClass<? > defineClass(String name,byte[] b, int off, int len,
                                         ProtectionDomain protectionDomain)
        throwsClassFormatError { protectionDomain = preDefineClass(name, protectionDomain); String source = defineClassSourceLocation(protectionDomain); Class<? > c = defineClass1(name, b, off, len, protectionDomain, source); postDefineClass(c, protectionDomain);return c;
    }
    
        /* Determine protection domain, and check that: - not define java.* class, - signer of this class matches signers for the rest of the classes in package. */
    private ProtectionDomain preDefineClass(String name, ProtectionDomain pd)
    {
        if(! checkName(name))throw new NoClassDefFoundError("IllegalName: " + name);

        // Note: Checking logic in java.lang.invoke.MemberName.checkForTypeAlias
        // relies on the fact that spoofing is impossible if a class has a name
        // of the form "java.*"
        if((name ! =null) && name.startsWith("java.")) {
            throw new SecurityException
                ("Prohibited package name: " +
                 name.substring(0, name.lastIndexOf('. ')));
        }
        if (pd == null) {
            pd = defaultDomain;
        }

        if(name ! =null) checkCerts(name, pd.getCodeSource());

        return pd;
    }
Copy the code

conclusion

1: any custom ClassLoader will eventually call classloader.defineclass. 2: classloader.defineclass will check for the class name, which is Java. If it starts, it will not be loaded

PS

Online articles don’t have to be trustworthy, but be skeptical