最近在研究类加载器,看到很多有关自定义类加载器的方法。有关“能否自定义类加载器加载java.lang.String”有争议,于是我实现了一下:
首先实现自定义类加载器可以通过实现两个方法来做:1 findClass 2 loadClass
首先看findClass
如果实现这个方法,那么样例代码如下:
然后再查看defineclass发现defineclass是classloader的方法,方法如下:
protected final Class> defineClass(String name, byte[] b, int off, int len)
throws ClassFormatError
{
return defineClass(name, b, off, len, null);
}
注意这个是final方法,同样defineclass都是final方法。java编程思想中解释final如下:
“使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“
所以,这个defineclass是无法让子类实现的,所以生成类的方法一定要用ClassLoader里面的defineClass
然后我们再看defineClass:
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;
}
发现有preDefineClass方法,再看此方法:
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;
}
重点代码已加黑,发现一java开头的都会抛出异常。因此只要在findClass方法里面创建class,就逃不过这个方法,所以创建自定义的java.lang.xcxxxxxx都不行
另外一种实现自定义加载的是重写loadClass方法,重写这个方法可以破坏双亲委派模型:java中的loadClass方法如下:
protected 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;
}
}
我们在红色代码不用父类加载器即可破坏双亲原则,但是只要生成一个类,就逃不过defineClass方法,所以,无法通过自定义类加载器来实现java.xxxxxx的类加载