类加载机制
源码一 Launcher类
public class Launcher {
// 有java虚拟机调用该方法获取到类加载器, 这个方法一般为jvm调用(C++调用)
public static Launcher getLauncher() {
return launcher;
}
public Launcher() {
// 扩展类加载器
Launcher.ExtClassLoader var1;
try {
// 实例化类扩展类加载器
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
// 实例化 应用程序类加载器 这个把 ExtClassLoader传过去,设置为AppClassLoader的父类
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
// 设置当前类加载器(这里可以看出,当前类的加载器为 AppClassLoader)
Thread.currentThread().setContextClassLoader(this.loader);
// 实例化权限控制类一般为关闭状态, 需要自己设定安全策略
String var2 = System.getProperty("java.security.manager");
if (var2 != null) {
SecurityManager var3 = null;
if (!"".equals(var2) && !"default".equals(var2)) {
try {
var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
} catch (IllegalAccessException var5) {
} catch (InstantiationException var6) {
} catch (ClassNotFoundException var7) {
} catch (ClassCastException var8) {
}
} else {
var3 = new SecurityManager();
}
if (var3 == null) {
throw new InternalError("Could not create SecurityManager: " + var2);
}
System.setSecurityManager(var3);
}
}
// 这个方法我们可以知道 Launcher的类加载器为AppClassLoader
public ClassLoader getClassLoader() {
return this.loader;
}
}
通过源码分析,我们可以看到java虚拟机启动的时候初始化了两个类型的classLoader : ExtClassLoader
和 AppClassLoader
, 接下来我们来看一下他们的实现类。
ExtClassLoader
static class ExtClassLoader extends URLClassLoader {
// 单例模式
private static volatile Launcher.ExtClassLoader instance;
// 这里通过单例模式实例化 ExtClassLoader
public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
if (instance == null) {
Class var0 = Launcher.ExtClassLoader.class;
synchronized(Launcher.ExtClassLoader.class) {
if (instance == null) {
instance = createExtClassLoader();
}
}
}
return instance;
}
// 这里可以看到 ExtClassLoader 的父加载器为null
public ExtClassLoader(File[] var1) throws IOException {
super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
}
}
AppClassLoader
static class AppClassLoader extends URLClassLoader {
final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
// 获取类路径
final String var1 = System.getProperty("java.class.path");
final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
public Launcher.AppClassLoader run() {
URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
return new Launcher.AppClassLoader(var1x, var0);
}
});
}
}
MyClassLoader
static class MyClassLoader extends ClassLoader {
private final String classPath;
public MyClassLoader(String classPath) {
this.classPath = classPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadByName(name);
return defineClass(name, data, 0, data.length);
} catch (IOException e) {
throw new ClassNotFoundException();
}
}
}
ClassLoader继承图
图中可以看出所有类都继承了ClassLoader
类,那我们现在来看一下ClassLoader类
public abstract class ClassLoader {
// 允许传入父ClassLoader
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}
// 没有传入父ClassLoader
protected ClassLoader() {
this(checkCreateClassLoader(), getSystemClassLoader());
}
// 获取默认的父ClassLoader
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() {
if (!sclSet) {
if (scl != null)
throw new IllegalStateException("recursive invocation");
sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
if (l != null) {
Throwable oops = null;
// 前面说过,Launcher 的 ClassLoader为 AppClassLoader
scl = l.getClassLoader();
try {
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;
}
}
}
从上面的源码分析可以一步一步的确认各个类加载器的父加载器,现在我们画一张图说明,这个后面的类加载器的双亲委派知己有关
BootstrapClassLoader
这个为引导程序加载器,在java中获取不到该类,jer/lib包下面的核心类都由该加载器加载。
ClassLoader双亲委派机制
ClassLoader中关于双亲委派机制的实现方法
public abstract class ClassLoader {
// 该方法为实现实现自定义查找类的方法
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
// 类加载方法
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;
}
}
// 通过引导类加载器加载类
private Class<?> findBootstrapClassOrNull(String name)
{
if (!checkName(name)) return null;
return findBootstrapClass(name);
}
// JIN调用(C++调用)
private native Class<?> findBootstrapClass(String name);
}
ClassLoader的父子关系以及双亲委派机制
加载流程说明:
首先由自定义类加载器调用 MyClassLoader#loadClass
加载类,这个时候调用ClassLoader#loadClass
方法,接着通过 JIN 调用ClassLoader#``findLoadedClass
来判断是否加载过该类,加载过则直接返回,否则调用parent加载类,一直调用到根加载器 ExtClassLoader 没有的话调用引导类加载器加载,没有找到的话,从 ExtClassLoser 开始依次调用findClass方法查找该类进行加载。