git
github.com/fw103699437…
java.lang.String分支
前言
老问题了,到网上也一搜一堆答案,比如,随便来一篇
乍一看好像没什么问题,但是在掌握自定义类加载器之后,知道如何打破双亲委派之后再回头来看这段话发现有两个问题:
1:凭什么你认为我现在是ApplicationClassLoader? 毕竟很多框架都会自定义类加载器的
2: 凭什么你认为我一定要走双亲委派?
怀疑当然要有个证据,那么我们就写一段程序:
1:打破双亲委派
2:写一个java.lang.String类
代码见git
《2020最新Java基础精讲视频教程和学习路线!》
一些重要的地方截取出来看看
package java.lang;
public class String {
private Integer a;
public Integer getA() {
return a;
}
public void setA(Integer a) {
this.a = a;
}
}
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 new RuntimeException(e);
}
}
}
package org.wayne;
public class RegisterDriverUtil {
public void register(String name) throws ClassNotFoundException {
Class.forName(name);
}
}
public static void test8(){
EnvironmentUtil.setEnv(EnvEnum.A);
RegisterDriverUtil.register("java.lang.String");
EnvironmentUtil.clearEnv();
}
打包,在wsl下运行,结果如下
推测:
1:代码里是用自定义类加载器直接加载的java.lang.String类,并没有走双亲委派
2:由报错来看,是java.lang.ClassLoader阻止了加载
原因
无论何种自定义类加载器,最后都是调用的defineClass方法加载byte[],注释如下
protected final Class<?> defineClass(String name, byte[] b, int off, int len,
ProtectionDomain protectionDomain)
throws ClassFormatError
{
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;
}
结论
1:无论何种自定义类加载器,最终都会调用ClassLoader.defineClass
2:ClassLoader.defineClass中会检查类名,类名以java.开头的,不予加载
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。