1.getSystemClassLoader方法
private static ClassLoader scl;
@CallerSensitive
public static ClassLoader getSystemClassLoader() {
//初始化系统类加载器
initSystemClassLoader();
if (scl == null) {
return null;
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkClassLoaderPermission(scl, Reflection.getCallerClass());
}
return scl;
}
private static synchronized void initSystemClassLoader() {
//scl是一个ClassLoader的对象,代表着系统类加载器,scl全称systenClassLoader
//已经设置的话就不进行以下操作
if (!sclSet) {
//没有进行设置,但是scl != null,这是不应该的所以报错
if (scl != null)
/*
Launcher类如果是Eclipse的朋友是看不到源码的,可以去看OpenJDK的代码
以下是Launcher类的代码,它的构造方法是私有的,只能通过getLauncher()得到该类的实例
private ClassLoader loader;这个成员存的是系统类加载器
private static Launcher launcher = new Launcher();
public static Launcher getLauncher() {
return launcher;
}
在其私有构造方法中你只需要知道做了三件事,1.创建了扩展类加载器 2.利用扩展类加载器创建了系统类加载器
3.将系统类加载器作为初始线程的上下文加载器
*/
sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
if (l != null) {
Throwable oops = null;
//得到系统类加载器
scl = l.ge
//doPrivileged方法十个native方法,它会执行其参数的run方法,
//最终我们会得到一个应用类加载器,该应用类加载器可能是系统类加载器,也可是我们自己定义的类加载器
scl = AccessController.doPrivileged(
new SystemClassLoaderAction(scl));
} catch (PrivilegedActionException pae) {
oops = pae.getCause();
if (oops instanceof InvocationTargetException) {
oops = oops.getCause();
}
}
if (oops != null) {
if (oops instanceof Error) {
throw (Error) oops;
} else {
// wrap the exception
throw new Error(oops);
}
}
}
sclSet = true;
}
}
class SystemClassLoaderAction
implements PrivilegedExceptionAction<ClassLoader> {
private ClassLoader parent;
SystemClassLoaderAction(ClassLoader parent) {
this.parent = parent;
}
public ClassLoader run() throws Exception {
/*
我们自己写的自定义类加载器也可以作为应用类加载器,只需要进行以下操作,或者在命令行更改
System.setProperty("java.system.class.loader","自定义类加载器的全权限定名");
*/
String cls = System.getProperty("java.system.class.loader");
//如果没有,将该系统类加载器返回即可
if (cls == null) {
return parent;
}
/*
如果有我们自己的定义的类加载,要先对它进行类加载会得到一个Class<?>对象,再利用反射机制得到单参数构造方法
执行该构造方法,这块的目的是将parent作为了自定义类加载器的父加载器。
并把自定义类加载器设置为当前线程的上下文类加载器
这块类加载用到了Class.forName(cls, true, parent)方法,稍后我们会进行讲解
*/
Constructor<?> ctor = Class.forName(cls, true, parent)
.getDeclaredConstructor(new Class<?>[] { ClassLoader.class });
ClassLoader sys = (ClassLoader) ctor.newInstance(
new Object[] { parent });
Thread.currentThread().setContextClassLoader(sys);
return sys;
}
}
forName()方法
对于Class.forName方法,我相信大多数人都是从JDBC连接数据库时了解到的,当时其实没有学过类加载器,所有并不知道这个方法的用意,今天分析一下它的源码。
forName()方法有两种
public static Class<?> forName(String className);
public static Class<?> forName(String name, boolean initialize,ClassLoader loader);
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
Class<?> caller = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// Reflective call to get caller class is only needed if a security manager
// is present. Avoid the overhead of making this call otherwise.
//getCallerClass()该方法是一个native方法,作用是得到调用这个forName方法的Class<?>对象
caller = Reflection.getCallerClass();
if (sun.misc.VM.isSystemDomainLoader(loader)) {
//得到加载调用者的类加载器
ClassLoader ccl = ClassLoader.getClassLoader(caller);
if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
//这是个native方法作用加载名字为name的类,并返回它的Calss<?>对象
return forName0(name, initialize, loader, caller);
}
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
//得到调用该方法的Class<?>对象
Class<?> caller = Reflection.getCallerClass();
//forName0方法是一个native方法,最终会使用加载了调用者类的类加载器来加载className所对应的类
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
总结 forName方法如果没有传入类加载器,会使用最终会使用加载了调用者类的类加载器来加载所对应的类