Java ClassLoader 源码解读
AppClassLoader loadClass
public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
int var3 = var1.lastIndexOf(46); //检查 类的 全路径中是否含有 . 号
if (var3 != -1) { //含有 . 号
SecurityManager var4 = System.getSecurityManager();
if (var4 != null) {
var4.checkPackageAccess(var1.substring(0, var3)); //检查 类 所在的 包(目录) 是否可以访问
}
}
if (this.ucp.knownToNotExist(var1)) {
Class var5 = this.findLoadedClass(var1);
if (var5 != null) {
if (var2) {
this.resolveClass(var5);
}
return var5;
} else {
throw new ClassNotFoundException(var1);
}
} else {
return super.loadClass(var1, var2);//到 ClassLoader 的 loadClass 里面
}
}
ClassLoader
ClassLoader 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) { //没有加载到的话 ,执行 findClass 方法
// 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;
}
}
ClassLoader findClass
注意这个方法,实际的实现需要在子类 URLClassLoader 里面查看
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
Launcher getLauncher 过程
注意在 getLauncher 之后的 AppClassLoader 对象之后,AppClassLoader 中的 ucp(urlClassPath )loaders 对象的size 是0
但是在用户程序里面 使用 Thread.currentThread().getContextClassLoader(); 可以看到 ucp.loaders size 已经不是0了,里面是 classpath的东西了
public Launcher() {
Launcher.ExtClassLoader var1;
try {
var1 = Launcher.ExtClassLoader.getExtClassLoader(); //拿到 ExtClassLoader 对象
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); //拿到 AppClassLoader 对象
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
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);
}
}
URLClassLoader
注意 本类的这块代码,在 ExtClassLoader 初始化过程中的父类URLClassLoader会执行这块代码
所以在 AppClassLoader 的 ucp 对象属性中 可以拿到 ExtClassLoader 的 父类URLClassLoader 的 ucp 的值
此时ucp的值就是 [C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext;C:\windows\Sun\Java\lib\ext] 目录中的所有的文件(除了meta-index文件)都放到 URL 对象数组中
static {
SharedSecrets.setJavaNetAccess(new JavaNetAccess() {
public URLClassPath getURLClassPath(URLClassLoader var1) {
return var1.ucp;
}
public String getOriginalHostName(InetAddress var1) {
return var1.holder.getOriginalHostName();
}
});
ClassLoader.registerAsParallelCapable();
}
URLClassLoader findClass
protected Class<?> findClass(final String name)
throws ClassNotFoundException
{
final Class<?> result;
try {
result = AccessController.doPrivileged(
new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws ClassNotFoundException {
String path = name.replace('.', '/').concat(".class");
//到 ucp(URLClassPath) 里面查找 resource,(到 java classpath jar中依次查找)
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
return defineClass(name, res);//找到这个 class 的话,到 defineClass 执行(这个方法就是 读取 class 文件,产生 class 对象)
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
} else {
return null;
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
if (result == null) {
throw new ClassNotFoundException(name);
}
return result;
}
Launcher.ExtClassLoader 实例话过程
可以看出 ExtClassLoader 集成自 URLClassLoader 类, URLClassLoader 中持有一个 ucp(URLClassPath,用来维护 classpath)
static class ExtClassLoader extends URLClassLoader {
private static volatile Launcher.ExtClassLoader instance;
//调用这个方法 获取 Launcher.ExtClassLoader 实力
public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
if (instance == null) {//检查是否已经存在 Launcher.ExtClassLoader 的实例没有
Class var0 = Launcher.ExtClassLoader.class;
synchronized(Launcher.ExtClassLoader.class) { //类锁,防止多次 执行
if (instance == null) {
instance = createExtClassLoader(); //创建 Launcher.ExtClassLoader 过程
}
}
}
return instance; //返回创建好的实例
}
//创建 Launcher.ExtClassLoader 过程
private static Launcher.ExtClassLoader createExtClassLoader() throws IOException {
try {
return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
public Launcher.ExtClassLoader run() throws IOException {
File[] var1 = Launcher.ExtClassLoader.getExtDirs(); //获取 配置的 java.ext.dirs (java的ext目录)中的 多个路径 的 File 对象数组
//[C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext;C:\windows\Sun\Java\lib\ext]
int var2 = var1.length;
for(int var3 = 0; var3 < var2; ++var3) {
MetaIndex.registerDirectory(var1[var3]); //目前来看没有什么作用
}
return new Launcher.ExtClassLoader(var1); //使用构造方法 构造 Launcher.ExtClassLoader 对象
}
});
} catch (PrivilegedActionException var1) {
throw (IOException)var1.getException();
}
}
//增加claspath 路径,使用父类 URLClassLoader 的 方法,最终增加到 父类的类变量 ucp 中(URLClassPath,用来维护 classpath)
void addExtURL(URL var1) {
super.addURL(var1);
}
public ExtClassLoader(File[] var1) throws IOException {
//getExtURLs(var1) [C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext;C:\windows\Sun\Java\lib\ext] 目录中的所有的文件(除了meta-index文件)都放到 URL 对象数组中
super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
}
//获取 配置的 java.ext.dirs (java的ext目录)中的 多个路径 的 File 对象数组 【C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext;C:\windows\Sun\Java\lib\ext】
private static File[] getExtDirs() {
String var0 = System.getProperty("java.ext.dirs"); //C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext;C:\windows\Sun\Java\lib\ext
File[] var1;
if (var0 != null) {
StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator);
int var3 = var2.countTokens(); //var0以;号分割后的 数量
var1 = new File[var3]; //创建对应个数的 File 对象数组
for(int var4 = 0; var4 < var3; ++var4) {
var1[var4] = new File(var2.nextToken()); //初始化数组
}
} else {
var1 = new File[0];
}
return var1;
}
//[C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext;C:\windows\Sun\Java\lib\ext] 目录中的所有的文件(除了meta-index文件)都放到 URL 对象数组中
private static URL[] getExtURLs(File[] var0) throws IOException {
Vector var1 = new Vector();
for(int var2 = 0; var2 < var0.length; ++var2) {
String[] var3 = var0[var2].list();
if (var3 != null) {
for(int var4 = 0; var4 < var3.length; ++var4) {
if (!var3[var4].equals("meta-index")) {
File var5 = new File(var0[var2], var3[var4]);
var1.add(Launcher.getFileURL(var5));
}
}
}
}
URL[] var6 = new URL[var1.size()];
var1.copyInto(var6);
return var6;
}
public String findLibrary(String var1) {
var1 = System.mapLibraryName(var1);
URL[] var2 = super.getURLs();
File var3 = null;
for(int var4 = 0; var4 < var2.length; ++var4) {
URI var5;
try {
var5 = var2[var4].toURI();
} catch (URISyntaxException var9) {
continue;
}
File var6 = var5.getAuthority() == null ? (new File(var5)).getParentFile() : Paths.get(var5).toFile().getParentFile();
if (var6 != null && !var6.equals(var3)) {
String var7 = VM.getSavedProperty("os.arch");
File var8;
if (var7 != null) {
var8 = new File(new File(var6, var7), var1);
if (var8.exists()) {
return var8.getAbsolutePath();
}
}
var8 = new File(var6, var1);
if (var8.exists()) {
return var8.getAbsolutePath();
}
}
var3 = var6;
}
return null;
}
private static AccessControlContext getContext(File[] var0) throws IOException {
PathPermissions var1 = new PathPermissions(var0);
ProtectionDomain var2 = new ProtectionDomain(new CodeSource(var1.getCodeBase(), (Certificate[])null), var1);
AccessControlContext var3 = new AccessControlContext(new ProtectionDomain[]{var2});
return var3;
}
static {
ClassLoader.registerAsParallelCapable();
instance = null;
}
}
AppClassLoader 初始化过程
static class AppClassLoader extends URLClassLoader {
//此时ucp的值就是 AppClassLoader 父类 URLClassLoader 中的 ucp ,就是 【classpath 中的jar分割开来,组成 File 对象数组 ;再转化到 URL 对象数组】
final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
final String var1 = System.getProperty("java.class.path");//这个里面的值就是 java 启动的时候 classpath的值,一般包含 JAVA_HOME/lib 和 JAVA_HOME/lib/ext中的jar包
final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1); //classpath 中的jar分割开来,组成 File 对象数组
return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
public Launcher.AppClassLoader run() {
URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2); //classpath 中的jar分割开来,组成 File 对象数组 ;再转化到 URL 对象数组
return new Launcher.AppClassLoader(var1x, var0); //使用 AppClassLoader 构造方法 构造 AppClassLoader 对象,这里的var0就是Launcher.ExtClassLoader 实例
}
});
}
//var1 就是 classpath 的 URL 对象数组 ;var2 就是 Launcher.ExtClassLoader 实例
AppClassLoader(URL[] var1, ClassLoader var2) {
super(var1, var2, Launcher.factory);
this.ucp.initLookupCache(this); //这里 ucp(URLClassPath) 中的 lookupCacheURLs 设置为 classpath ;lookupCacheLoader 设置为 this
}
// Class.forName 的 入口
public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
int var3 = var1.lastIndexOf(46);
if (var3 != -1) {
SecurityManager var4 = System.getSecurityManager();
if (var4 != null) {
var4.checkPackageAccess(var1.substring(0, var3)); //检查jar包 是否可以访问
}
}
if (this.ucp.knownToNotExist(var1)) {//使用 ucp(URLClassPath) 看 是否可以 使用自己的 加载器 加载,当然是false了,这里详细的逻辑参考下面的URLClassPath
Class var5 = this.findLoadedClass(var1);
if (var5 != null) {
if (var2) {
this.resolveClass(var5);
}
return var5;
} else {
throw new ClassNotFoundException(var1);
}
} else {//使用父类加载器 加载
//这个方法在 超级父类 ClassLoader 中,先试用 自己的 parent classloader(Launcher.ExtClassLoader) 加载,
//加载不到的话,再使用 父类 URLClassLoader 的 findClass 方法,findClass 是找到 这个 class 在那个jar包
//findClass 方法里面在找到 这个jar包之后
return super.loadClass(var1, var2);
}
}
protected PermissionCollection getPermissions(CodeSource var1) {
PermissionCollection var2 = super.getPermissions(var1);
var2.add(new RuntimePermission("exitVM"));
return var2;
}
private void appendToClassPathForInstrumentation(String var1) {
assert Thread.holdsLock(this);
super.addURL(Launcher.getFileURL(new File(var1)));
}
private static AccessControlContext getContext(File[] var0) throws MalformedURLException {
PathPermissions var1 = new PathPermissions(var0);
ProtectionDomain var2 = new ProtectionDomain(new CodeSource(var1.getCodeBase(), (Certificate[])null), var1);
AccessControlContext var3 = new AccessControlContext(new ProtectionDomain[]{var2});
return var3;
}
static {
ClassLoader.registerAsParallelCapable();
}
}
URLClassPath
public URLClassPath(URL[] var1, URLStreamHandlerFactory var2, AccessControlContext var3) {
this.path = new ArrayList();
this.urls = new Stack();
this.loaders = new ArrayList();
this.lmap = new HashMap();
this.closed = false;
for(int var4 = 0; var4 < var1.length; ++var4) {
this.path.add(var1[var4]);
}
this.push(var1); //看这里 把 所以的 依赖jar 都加入到 urls 属性中
if (var2 != null) {
this.jarHandler = var2.createURLStreamHandler("jar");
}
if (DISABLE_ACC_CHECKING) {
this.acc = null;
} else {
this.acc = var3;
}
}
URLClassPath getResource
public Resource getResource(String var1, boolean var2) {
if (DEBUG) {
System.err.println("URLClassPath.getResource(\"" + var1 + "\")");
}
int[] var4 = this.getLookupCache(var1);//这个方法返回为 null
URLClassPath.Loader var3;
for(int var5 = 0; (var3 = this.getNextLoader(var4, var5)) != null; ++var5) {//到getNextLoader 拿到 URLClassPath.Loader
Resource var6 = var3.getResource(var1, var2);//依次遍历 classpath jar ,如果里面有 目标的 class 文件,则返回
if (var6 != null) {
return var6;
}
}
return null;
}
URLClassPath getLookupCache
private synchronized int[] getLookupCache(String var1) {
if (this.lookupCacheURLs != null && lookupCacheEnabled) { //因为 lookupCacheEnabled 是 false,所以这个方法 返回 null
int[] var2 = getLookupCacheForClassLoader(this.lookupCacheLoader, var1);
if (var2 != null && var2.length > 0) {
int var3 = var2[var2.length - 1];
if (!this.ensureLoaderOpened(var3)) {
if (DEBUG_LOOKUP_CACHE) {
System.out.println("Expanded loaders FAILED " + this.loaders.size() + " for maxindex=" + var3);
}
return null;
}
}
return var2;
} else {
return null;
}
}
URLClassPath getNextLoader & getLoader
private synchronized URLClassPath.Loader getNextLoader(int[] var1, int var2) {
if (this.closed) {
return null;
} else if (var1 != null) {//一般 var1 就是 null
if (var2 < var1.length) {
URLClassPath.Loader var3 = (URLClassPath.Loader)this.loaders.get(var1[var2]);
if (DEBUG_LOOKUP_CACHE) {
System.out.println("HASCACHE: Loading from : " + var1[var2] + " = " + var3.getBaseURL());
}
return var3;
} else {
return null;
}
} else {
return this.getLoader(var2);//到这个方法来
}
}
private synchronized URLClassPath.Loader getLoader(int var1) {
if (this.closed) {
return null;
} else {
//当this.loaders.size() 小于 遍历次数的时候
while(this.loaders.size() < var1 + 1) { //this.loaders.size() 一般是 12
URL var2;
synchronized(this.urls) {
if (this.urls.empty()) { //这个 urls,已经在 构造方法里面初始化了
return null;
}
var2 = (URL)this.urls.pop(); //弹出一个 URL
}
String var3 = URLUtil.urlNoFragString(var2);
if (!this.lmap.containsKey(var3)) {
URLClassPath.Loader var4;
try {
var4 = this.getLoader(var2); //拿到这个 URL的 URLClassPath.Loader
URL[] var5 = var4.getClassPath();
if (var5 != null) {
this.push(var5);
}
} catch (IOException var6) {
continue;
} catch (SecurityException var7) {
if (DEBUG) {
System.err.println("Failed to access " + var2 + ", " + var7);
}
continue;
}
this.validateLookupCache(this.loaders.size(), var3);
this.loaders.add(var4);
this.lmap.put(var3, var4);
}
}
if (DEBUG_LOOKUP_CACHE) {
System.out.println("NOCACHE: Loading from : " + var1);
}
return (URLClassPath.Loader)this.loaders.get(var1); //基本上 从 this.loaders 里面依次返回 (已经被jvm初始化过了,size是 classpath的数量)
}
}