深入理解JVM-类加载及类加载器 (11)

所有类加载器(除了启动类加载器)都被时限为Java类。不过,中国要有一个组件来加载第一个Java类加载器,从而让整个过程能够顺利的进行下去,加载第一个纯Java类加载器就是启动类加载器的职责。

启动类加载器还会负责加载供JRE正常运行所需要的基本组件,这包括java.util与java.lang包中的内容。

sout(ClassLoader.class.getClassLoader()); > 输出结果: null // 因为ClassLoader是由启动类加载器的加载的。 ExtClassLoader 和 APPCLassLoader 位于 Launcher.class中的静态内部类。 sout(Launcher.class.getClassLoader()); > 输出结果: null // 因为扩展类加载器与应用类加载器也是由启动类加载器的加载的。 自定义系统类加载器

image-20200211061413889

image-20200211061508983

image-20200211061353721

在自定义类加载器中加一个父类的构造方法,就可以正常的运行了。

用Java命令行的话,和idea里边执行的结果有时候类加载器的是不一样的。

因为idea也重新定义了类加载器的路径。

getSystemClassLoader(); java.lang.ClassLoader public static ClassLoader getSystemClassLoader() Returns the system class loader for delegation. This is the default delegation parent for new ClassLoader instances, and is typically the class loader used to start the application. // 通常 系统类加载器用来加载我们的应用。 This method is first invoked early in the runtimes startup sequence, at which point it creates the system class loader and sets it as the context class loader of the invoking Thread. // 这个方法会创建系统类加载器,并将AppClassLoader设置为上下文类加载器 The default system class loader is an implementation-dependent instance of this class. If the system property "java.system.class.loader" is defined when this method is first invoked then the value of that property is taken to be the name of a class that will be returned as the system class loader. The class is loaded using the default system class loader and must define a public constructor that takes a single parameter of type ClassLoader which is used as the delegation parent. An instance is then created using this constructor with the default system class loader as the parameter. The resulting class loader is defined to be the system class loader. // 如果我们自定义了 java.system.class.loader。 那么就会把这个值当做系统类加载器。这个类是被AppClassLoader加载器加载器的。这个自定义的系统类加载器必须要有一个 带有父加载器参数的构造方法。 If a security manager is present, and the invoker's class loader is not null and the invoker's class loader is not the same as or an ancestor of the system class loader, then this method invokes the security managers checkPermission method with a RuntimePermission("getClassLoader") permission to verify access to the system class loader. If not, a SecurityException will be thrown. @CallerSensitive 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; scl = l.getClassLoader(); // 返回了AppClassLoader try { // 已经获取到了 scl 为什么还要进行一步这样的操作呢? // 加载自定义系统类加载器的属性。如果自定义了系统类加载器,在这里进行了处理,如果没有的话,则使用默认的系统类加载器。(可以点进去看看,里边的run方法摘抄出来放下了下方) 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; //设置成功了 } } // 处理自定义加载器的方法。 public ClassLoader run() throws Exception { String cls = System.getProperty("java.system.class.loader"); if (cls == null) {// 如果设置了自定义加载器的属性,则不为null,进行后续的操作。 return parent; } // 在下方,会单独讲解一下 Class.forName方法的使用。 Constructor<?> ctor = Class.forName(cls, true, parent) .getDeclaredConstructor(new Class<?>[] { ClassLoader.class }); ClassLoader sys = (ClassLoader) ctor.newInstance( //获取到自定义的类加载器。返回 new Object[] { parent }); Thread.currentThread().setContextClassLoader(sys); return sys; }

grepcode.com 在线查看源代码的网站。

为什么扩展类加载的路径是java.ext.dirs 源代码里边写的。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpszsp.html