张治峰的博客

JDK源码级别理解双亲委派机制

2021-01-02

java 启动流程

先来一个java 代码

public class Test {

public static void main(String[] args) {

System.out.println("hello world");
}
}

先通过javac 编译 然后使用 java 命令启动,流程图如下:

接下来我们根据流程图进行源码分析,hotspot 启动入口为 java.c 文件中的JavaMain(void * _args)

JavaMain(void * _args)

JavaMain(void * _args)
{
.......
// 加载主类
mainClass = LoadMainClass(env, mode, what);

.......
// 获取 main 函数
mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
"([Ljava/lang/String;)V");

........

// 获取启动类的main 方法
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);

........
// 执行启动类的main 方法
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);

........
// 结束并销毁虚拟机
LEAVE();
}

LoadMainClass

java.c#LoadMainClass(JNIEnv *env, int mode, char *name) 加载启动类

LoadMainClass(JNIEnv *env, int mode, char *name)
{
......
// 获取 LauncherHelper 类 sun/launcher/LauncherHelper(java类)
jclass cls = GetLauncherHelperClass(env);
NULL_CHECK0(cls);
if (JLI_IsTraceLauncher()) {
start = CounterGet();
}

// 获取 LauncherHelper 的静态方法 checkAndLoadMain 方法 赋值给mid
NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,
"checkAndLoadMain",
"(ZILjava/lang/String;)Ljava/lang/Class;"));
.....
str = NewPlatformString(env, name);

// 调用 LauncherHelper 的静态方法 checkAndLoadMain 方法 即(mid方法)
CHECK_JNI_RETURN_0(
result = (*env)->CallStaticObjectMethod(
env, cls, mid, USE_STDERR, mode, str));

if (JLI_IsTraceLauncher()) {
end = CounterGet();
printf("%ld micro seconds to load main class\n",
(long)(jint)Counter2Micros(end-start));
printf("----%s----\n", JLDEBUG_ENV_ENTRY);
}

return (jclass)result;
}

GetLauncherHelperClass

获取java 类 sun/launcher/LauncherHelper 实例

GetLauncherHelperClass(JNIEnv *env)
{
if (helperClass == NULL) {
NULL_CHECK0(helperClass = FindBootStrapClass(env,
"sun/launcher/LauncherHelper"));
}
return helperClass;
}

CheckAndLoadMain

调用java 类 sun/launcher/LauncherHelper 的静态方法 checkAndLoadMain 检查启动类并返回.

public static Class<?> checkAndLoadMain(boolean printToStderr,
int mode,
String what) {
initOutput(printToStderr);
// get the class name
String cn = null;
// 判断java 命令 运行模式为 指定类启动 还是 指定 jar 并获取运行主类(我们使用的java com.jvm.classloader.Test 及 类方式运行)
switch (mode) {
case LM_CLASS:
cn = what;
break;
case LM_JAR:
// jar 包方式启动从jar 包中获取 主类 (感兴趣的同学自行点击方法进行查看获取细节)
cn = getMainClassFromJar(what);
break;
default:
// should never happen
throw new InternalError("" + mode + ": Unknown launch mode");
}
// 将文件路径 / 换成. 即改成类的全限定名
cn = cn.replace('/', '.');
Class<?> mainClass = null;
try {
// 通过类加载器加载启动类
//scloader 为 LauncherHelper 的一个 静态常量
//private static final ClassLoader scloader =
// ClassLoader.getSystemClassLoader();
// ClassLoader.getSystemClassLoader() 源码看右侧->App及Ext类加载器初始化 getSystemClassLoader()
// 看面类加载器初始化可知 scloader 为 AppClassLoader
// ClassLoader.getSystemClassLoader() 源码看右侧->类加载源码 ClassLoader.loader
mainClass = scloader.loadClass(cn);
} catch (NoClassDefFoundError | ClassNotFoundException cnfe) {
if (System.getProperty("os.name", "").contains("OS X")
&& Normalizer.isNormalized(cn, Normalizer.Form.NFD)) {
try {
// On Mac OS X since all names with diacretic symbols are given as decomposed it
// is possible that main class name comes incorrectly from the command line
// and we have to re-compose it
mainClass = scloader.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC));
} catch (NoClassDefFoundError | ClassNotFoundException cnfe1) {
abort(cnfe, "java.launcher.cls.error1", cn);
}
} else {
abort(cnfe, "java.launcher.cls.error1", cn);
}
}
// set to mainClass
// 将 LauncherHelper 的属性指向 主类
appClass = mainClass;

/*
* Check if FXHelper can launch it using the FX launcher. In an FX app,
* the main class may or may not have a main method, so do this before
* validating the main class.
*/
// 判断是不是特殊的类 进行其他处理 (跳过)
if (mainClass.equals(FXHelper.class) ||
FXHelper.doesExtendFXApplication(mainClass)) {
// Will abort() if there are problems with the FX runtime
FXHelper.setFXLaunchParameters(what, mode);
return FXHelper.class;
}
// 校验主类信息是否完整:是否名字为main 的静态方法
validateMainClass(mainClass);
// 返回主类信息 及返回 上述 到c++ 代码中
return mainClass;
}

GetStaticMethodID

javac#javaMain 方法中 获取启动类的main 方法

mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
"([Ljava/lang/String;)V");

执行启动类的main 方法

(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);

结束并销毁虚拟机

LEAVE();

App及Ext类加载器初始化

刚才有个主类加载 mainClass = scloader.loadClass(cn); 属性 scloader = ClassLoader.getSystemClassLoader(); 下面我们就ClassLoader.getSystemClassLoader()方法继续跟进
这一块是类加载链的创建过程

getSystemClassLoader()

java类: java.lang.ClassLoader#getSystemClassLoader()

public static ClassLoader getSystemClassLoader() {
// 初始化系统类加载器
initSystemClassLoader();

if (scl == null) {
return null;
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkClassLoaderPermission(scl, Reflection.getCallerClass());
}
return scl;
}

initSystemClassLoader()

java类调用 java.lang.ClassLoader#initSystemClassLoader()

private static synchronized void initSystemClassLoader() {
// 类加载器 是否初始化完成 (该方法结束后会把值 设置成 true)
if (!sclSet) {
// scl 不等于空说明 初始化过过了 抛异常(个人觉得一般不会出现这种问题 只是让逻辑更加严谨)
if (scl != null)
throw new IllegalStateException("recursive invocation");
// 获取 启动工具类
sun.misc.Launcher l = sun.misc.Launcher.getLauncher();

if (l != null) {
Throwable oops = null;
// 获取类加载器 此处为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;
}
}

Launcher#getLauncher()

sun.misc.Launcher#getLauncher()

public class Launcher {
private static URLStreamHandlerFactory factory = new Factory();
private static Launcher launcher = new Launcher();
private static String bootClassPath =
System.getProperty("sun.boot.class.path");

public static Launcher getLauncher() {
return launcher;
}
......
}

public static Launcher getLauncher() {
// launcher 是 Launcher 类的静态属性
// private static Launcher launcher = new Launcher();
return launcher;
}

Launcher#Launcher()

sun.misc.Launcher#Launcher()

public Launcher() {
// Create the extension class loader
ClassLoader extcl;
try {
// 创建 ExtClassLoader 对象
extcl = ExtClassLoader.getExtClassLoader();
} catch (IOException e) {
throw new InternalError(
"Could not create extension class loader", e);
}

// Now create the class loader to use to launch the application
try {
// 创建 AppClassLoader 并把 ExtClassLoader 对象 extcl 传入(设置AppClassLoader 的 parent 为 extcl)
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader", e);
}

// Also set the context class loader for the primordial thread.
Thread.currentThread().setContextClassLoader(loader);

// Finally, install a security manager if requested
String s = System.getProperty("java.security.manager");
if (s != null) {
// init FileSystem machinery before SecurityManager installation
sun.nio.fs.DefaultFileSystemProvider.create();

SecurityManager sm = null;
if ("".equals(s) || "default".equals(s)) {
sm = new java.lang.SecurityManager();
} else {
try {
sm = (SecurityManager)loader.loadClass(s).newInstance();
} catch (IllegalAccessException e) {
} catch (InstantiationException e) {
} catch (ClassNotFoundException e) {
} catch (ClassCastException e) {
}
}
if (sm != null) {
System.setSecurityManager(sm);
} else {
throw new InternalError(
"Could not create SecurityManager: " + s);
}
}
}

getExtClassLoader()

ExtClassLoader.getExtClassLoader();

// 单例获取 ExtClassLoader 实例对象
public static ExtClassLoader getExtClassLoader() throws IOException
{
if (instance == null) {
synchronized(ExtClassLoader.class) {
if (instance == null) {
instance = createExtClassLoader();
}
}
}
return instance;
}
createExtClassLoader()

ExtClassLoader#createExtClassLoader()

private static ExtClassLoader createExtClassLoader() throws IOException {
try {
// Prior implementations of this doPrivileged() block supplied
// aa synthesized ACC via a call to the private method
// ExtClassLoader.getContext().

return AccessController.doPrivileged(
new PrivilegedExceptionAction<ExtClassLoader>() {
public ExtClassLoader run() throws IOException {
// 获取ExtClassLoader 加载的 文件路径
final File[] dirs = getExtDirs();
int len = dirs.length;
for (int i = 0; i < len; i++) {
MetaIndex.registerDirectory(dirs[i]);
}
// 创建ExtClassLoader对象并返回
return new ExtClassLoader(dirs);
}
});
} catch (java.security.PrivilegedActionException e) {
throw (IOException) e.getException();
}
}

getAppClassLoader

AppClassLoader#getAppClassLoader(extcl) 这个方法将会把 AppClassLoader 的 parent 属性设置为 ExtClassLoader

public static ClassLoader getAppClassLoader(final ClassLoader extcl)
throws IOException
{
// 获取classpath 路径 也就是AppClassLoader 加载的类路径
final String s = System.getProperty("java.class.path");
final File[] path = (s == null) ? new File[0] : getClassPath(s);

// Note: on bugid 4256530
// Prior implementations of this doPrivileged() block supplied
// a rather restrictive ACC via a call to the private method
// AppClassLoader.getContext(). This proved overly restrictive
// when loading classes. Specifically it prevent
// accessClassInPackage.sun.* grants from being honored.
//
return AccessController.doPrivileged(
new PrivilegedAction<AppClassLoader>() {
public AppClassLoader run() {
URL[] urls =
(s == null) ? new URL[0] : pathToURLs(path);
// 返回AppClassLoader 实例对象 并传入 extclassLoader 对象
return new AppClassLoader(urls, extcl);
}
});
}
AppClassLoader

执行AppClassLoader构造方法 AppClassLoader#AppClassLoader(urls, extcl);

AppClassLoader(URL[] urls, ClassLoader parent) {
// 该方法调用URLClassLoader#URLClassLoader
super(urls, parent, factory);
ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
ucp.initLookupCache(this);
}

# URLClassLoader#URLClassLoader(urls, extcl);
public URLClassLoader(URL[] urls, ClassLoader parent,
URLStreamHandlerFactory factory) {
// 该方法调用SecureClassLoader#SecureClassLoader(ClassLoader parent)
super(parent);
// this is to make the stack depth consistent with 1.1
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
acc = AccessController.getContext();
ucp = new URLClassPath(urls, factory, acc);
}

#SecureClassLoader#SecureClassLoader(ClassLoader parent)

protected SecureClassLoader(ClassLoader parent) {
// 调用ClassLoader#ClassLoader(ClassLoader parent)
super(parent);
// this is to make the stack depth consistent with 1.1
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
initialized = true;
}

private ClassLoader(Void unused, ClassLoader parent) {
// 设置 parent 属性
this.parent = parent;
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
package2certs = new ConcurrentHashMap<>();
assertionLock = new Object();
} else {
// no finer-grained lock; lock on the classloader instance
parallelLockMap = null;
package2certs = new Hashtable<>();
assertionLock = this;
}
}

java.lang.ClassLoader#loadClass(String name)

public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}

java.lang.ClassLoader#loadClass(String name,boolean resolve)

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;
}
}

双亲委派源码解析

默认类加载器 加载入口为 java.lang.ClassLoader#loadClass

loadClass(String className)

public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}

loadClass(String name, boolean resolve)

java.lang.ClassLoader#loadClass(String name, boolean resolve)

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 {
// 获取类加载器的parent 属性 根据上面的App及Ext类加载器初始化 过程
// 我们知道 AppClassLoader 的 parent 为 ExtClassLoader
// ExtClassLoader 的 parent 为 null

// AppClassLoader parent 不等于null 所以会委托给 ExtClassLoader 加载类
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// ExtClassLoader类加载器的parent 为null 所以委托给 BootstrapClassLoader
// BootstrapClassLoader加载器是c++ 代码 所以 parent 为null 时就是
// 父加载器为BootstrapClassLoader
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();
// 调用类加载器的 findClass 方法加载类
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;
}
}
Tags: java
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章