GC Root有一种叫做System Class,官方解释“Class loaded by bootstrap/system class loader. For example, everything from the rt.jar like java.util. .”,大意是:被bootstrap/system加载器加载的类,比如,像java.util.这些来自rt.jar的类。
/** * 使用指定的二进制名称来加载类。默认的查找类的顺序如下: * 调用findLoadedClass(String) 检查这个类是否被加载过; * 调用父加载器的loadClass(String),如果父加载器为null,使用虚拟机内置的加载器代替; * 如果父类未找到,调用findClass(String)方法查找类。 */ // ClassLoader 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) { longt0= System.nanoTime(); try { // The parent class loader for delegation // Note: VM hardcoded the offset of this field, thus all new fields // must be added *after* it. 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. longt1= 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; } }
从源码中我们看到有三种类加载器:
引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码(C++)来实现的,并不继承自java.lang.ClassLoader。负责将${JAVA_HOME}/lib目录下和-Xbootclasspath参数所指定的路径中的,并且是Java虚拟机识别的(仅按照文件名识别,如rt.jar,不符合的类库即使放在lib下也不会被加载)类库加载到JVM内存中,引导类加载器无法被Java程序直接引用;
扩展类加载器(extensions class loader):它用来加载 Java 的扩展库(${JAVA_HOME}/ext),或者被java.ext.dirs系统变量所指定的路径中的所有类库;
系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载Java类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
每个Java类都维护着一个指向定义它的类加载器的引用,通过getClassLoader()方法就可以获取到此引用。通过调用getParent()方法可以得到加载器的父类,上述代码输出中,AppClassLoader对应系统类加载器(system class loader);ExtClassLoader对应扩展类加载器(extensions class loader);需要注意的是这里并没有输出引导类加载器,这是因为有些JDK的实现对于父类加载器是引导类加载器。这些加载器的父子关系通过组合实现。
// Worker method called by the public getConnection() methods. privatestatic Connection getConnection( String url, java.util.Properties info, Class<?> caller)throws SQLException { /* * 再次强调下:原始线程的上下文ClassLoader通常设定为用于加载应用程序的类加载器 * When callerCl is null, we should check the application's * (which is invoking this class indirectly) * classloader, so that the JDBC driver class outside rt.jar * can be loaded from here. */ //caller由Reflection.getCallerClass()得到,而调用方是java.sql.DriverManager,所以getClassLoader()是引导类加载器,也就是null //所以此处使用线程上下文加载器来加载实现类 ClassLoadercallerCL= caller != null ? caller.getClassLoader() : null; synchronized(DriverManager.class) { // synchronize loading of the correct classloader. if (callerCL == null) { callerCL = Thread.currentThread().getContextClassLoader(); } }
// Walk through the loaded registeredDrivers attempting to make a connection. // Remember the first exception that gets raised so we can reraise it. SQLExceptionreason=null;
for(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. // isDriverAllowed中使用给定的加载器加载指定的驱动 if(isDriverAllowed(aDriver.driver, callerCL)) { try { println(" trying " + aDriver.driver.getClass().getName()); Connectioncon= aDriver.driver.connect(url, info); if (con != null) { // Success! println("getConnection returning " + aDriver.driver.getClass().getName()); return (con); } } catch (SQLException ex) { if (reason == null) { reason = ex; } }