主要分析类加载类的方法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); //native-查找类是否已经被加载了
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name); //native-使用启动类加载器加载
}
} 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;
}
}
通过类全限定名查找是否已经加载了,如果还未加载,则使用父类加载器或者启动类加载器加载该类,如果仍然未加载到,则使用当前类加载器加载
类加载器是否有并发能力
getClassLoadingLock
获取一个对象作为锁,如果parallelLockMap为空,则表明loadClass中加锁的对象是当前类实例;否则表明加锁的对象是Object,且对于同一个className会获取到同样的Object对象
protected Object getClassLoadingLock(String className) {
Object lock = this;
if (parallelLockMap != null) {
Object newLock = new Object();
lock = parallelLockMap.putIfAbsent(className, newLock);
if (lock == null) {
lock = newLock;
}
}
return lock;
}
基于parallelLockMap对象,key是className,value是Object对象
private final ConcurrentHashMap<String, Object> parallelLockMap;
构造器
那么,parallelLockMap是哪里初始化的?
构造器初始化了的时候,但是受到isRegistered方法的控制
private ClassLoader(Void unused, ClassLoader parent) {
this.parent = parent;
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
package2certs = new ConcurrentHashMap<>();
domains =
Collections.synchronizedSet(new HashSet<ProtectionDomain>());
assertionLock = new Object();
} else {
// no finer-grained lock; lock on the classloader instance
parallelLockMap = null;
package2certs = new Hashtable<>();
domains = new HashSet<>();
assertionLock = this;
}
}
ParallelLoaders
该类是ClassLoader的内部静态类,用于实现当前的加载器被定位为具有并行能力,通过Set保存着类加载器实例,在set中的类加载器是具备并行能力的。结合getClassLoadingLocK。
private static class ParallelLoaders {
private ParallelLoaders() {}
// the set of parallel capable loader types
//保存类加载器实例
private static final Set<Class<? extends ClassLoader>> loaderTypes =
Collections.newSetFromMap(
new WeakHashMap<Class<? extends ClassLoader>, Boolean>());
static {
synchronized (loaderTypes) { loaderTypes.add(ClassLoader.class); }
}
/**
* Registers the given class loader type as parallel capabale.
* Returns {@code true} is successfully registered; {@code false} if
* loader's super class is not registered.
*/
//把类加载器实例存入set
static boolean register(Class<? extends ClassLoader> c) {
synchronized (loaderTypes) {
if (loaderTypes.contains(c.getSuperclass())) {
loaderTypes.add(c);
return true;
} else {
return false;
}
}
}
/**
* Returns {@code true} if the given class loader type is
* registered as parallel capable.
*/
//判断set是否有指定类加载器
static boolean isRegistered(Class<? extends ClassLoader> c) {
synchronized (loaderTypes) {
return loaderTypes.contains(c);
}
}
}
综上所述,在ParallelLoaders set中的类加载器是具备并行能力的,否则不具备。
注册
那么set中值怎么放进去的呢?
注册方法
在ClassLoader类中
@CallerSensitive
protected static boolean registerAsParallelCapable() {
Class<? extends ClassLoader> callerClass = //获取当前类加载器
Reflection.getCallerClass().asSubclass(ClassLoader.class);
return ParallelLoaders.register(callerClass); //注册到set中
}
URLClassLoader
在该类中有静态代码块,调用了上述注册方法
static {
sun.misc.SharedSecrets.setJavaNetAccess (
new sun.misc.JavaNetAccess() {
public URLClassPath getURLClassPath (URLClassLoader u) {
return u.ucp;
}
}
);
ClassLoader.registerAsParallelCapable();
}
以下这两个类加载器继承了URLClassLoader,因此,在使用这两个类加载器的时候也就具备上述注册的功能。其它类加载器类似。
扩展类加载器
static class ExtClassLoader extends URLClassLoader {
//...
}
应用程序类加载器
static class AppClassLoader extends URLClassLoader {
//...
}
全文倒序写,适合从下往上阅读。