sun.misc.launcher
Java仮想マシンのエントリ
ランチャーの初期化
private static URLStreamHandlerFactory factory = new Launcher.Factory();
private static Launcher launcher = new Launcher();
private static String bootClassPath = System.getProperty("sun.boot.class.path");
private ClassLoader loader;
private static URLStreamHandler fileHandler;
public Launcher() {
Launcher.ExtClassLoader var1;
try {
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} 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);
}
}
复制代码
Launcherコンストラクターのこのコードから、次の情報を取得できます。
- LauncherはExtClassLoaderとAppClassloaderを初期化し、ExtClassLoaderをAppClassloaderの親ローダーとして使用します(これは継承関係ではないことに注意してください)。
- ここで確認できるのは、BootstrapClassloaderがExtClassloaderの親ローダーとして明示的に使用されていないことです。ただし、クラスローダーのloadClassメソッドから、ネイティブメソッドが呼び出されることがわかります。ネイティブメソッドは、実際にはBootstrapClassloaderから取得されます(BootstrapClassloaderは実際にはC ++で実装されており、Classloaderを継承しないため)
- スレッドのデフォルトのクラスローダーをAppClassloaderに設定します
- BootstrapClassloaderはここでは初期化されませんが、一部のパッケージをロードするためのSystem.getProperty( "sun.boot.class.path")のようなコードが存在する可能性があります。
System.getProperty( "sum.boot.class.path")の内容を出力すると、bootstrapClassloaderの内容を確認できます。また、sun.misc.Launcher.getBootstrapClassPath()を介してパス情報を取得することもできます。
==> file:/C:/Program%20Files/Java/jdk1.8.0_201/jre/lib/resources.jar
==> file:/C:/Program%20Files/Java/jdk1.8.0_201/jre/lib/rt.jar
==> file:/C:/Program%20Files/Java/jdk1.8.0_201/jre/lib/sunrsasign.jar
==> file:/C:/Program%20Files/Java/jdk1.8.0_201/jre/lib/jsse.jar
==> file:/C:/Program%20Files/Java/jdk1.8.0_201/jre/lib/jce.jar
==> file:/C:/Program%20Files/Java/jdk1.8.0_201/jre/lib/charsets.jar
==> file:/C:/Program%20Files/Java/jdk1.8.0_201/jre/lib/jfr.jar
==> file:/C:/Program%20Files/Java/jdk1.8.0_201/jre/classes
复制代码
ここで初期化されたBootClassPathHolderもあります
private static class BootClassPathHolder {
static final URLClassPath bcp;
private BootClassPathHolder() {
}
static {
URL[] var0;
if (Launcher.bootClassPath != null) {
var0 = (URL[])AccessController.doPrivileged(new PrivilegedAction<URL[]>() {
public URL[] run() {
File[] var1 = Launcher.getClassPath(Launcher.bootClassPath);
int var2 = var1.length;
HashSet var3 = new HashSet();
for(int var4 = 0; var4 < var2; ++var4) {
File var5 = var1[var4];
if (!var5.isDirectory()) {
var5 = var5.getParentFile();
}
if (var5 != null && var3.add(var5)) {
MetaIndex.registerDirectory(var5);
}
}
return Launcher.pathToURLs(var1);
}
});
} else {
var0 = new URL[0];
}
bcp = new URLClassPath(var0, Launcher.factory, (AccessControlContext)null);
bcp.initLookupCache((ClassLoader)null);
}
}
复制代码
これが私の分析です:
- BootClassPath(つまり、System.getProperty( "sum.boot.class.path"))の場合、エグゼキュータはこれらのファイルを読み取り、File[]としてロードします。
- file []をトラバースしてパスかどうかを判断し、そうでない場合は、上位レベルのパスを取得します(D:/test/1.jar => D:/ test)
- 当不为null时,将其添加到set(用于去重)并判断是否添加成功。如果添加成功,则进入到MetaIndex.registerDirectory将路径传输进去,读取目录下meta-index(用来提供jvm启动的加载速度),并添加到jarMap里面。
- initLookupCache这个方法将查找到的classPath缓存到jvm中。其中null对应到的是bootstrapClassloader。这里后面有时间可以深入一下jvm的源码。
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();
int var2 = var1.length;
for(int var3 = 0; var3 < var2; ++var3) {
MetaIndex.registerDirectory(var1[var3]);
}
return new Launcher.ExtClassLoader(var1);
}
});
} catch (PrivilegedActionException var1) {
throw (IOException)var1.getException();
}
}
public ExtClassLoader(File[] var1) throws IOException {
super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
}
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;
}
复制代码
这里可以看出几点:
- ExtClassloader 的父加载器为null
- 加载路径为java.ext.dirs
- 初始化方式与BootClassPathHolder有相似的地方,都采用了meta-index记载
- ExtClassloader 继承了 URLClassloader
AppClassLoader
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);
}
});
}
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);
}
}
复制代码
这里可以看出:
- AppClassloader 加载路径为java.class.path
- 重载了一下loadClass方法
- 校验class文件
- 查找类是否存在