protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded // 1. 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。 Class<?> c = findLoadedClass(name); if (c == null) { longt0= System.nanoTime(); try { if (parent != null) { // 2. 判断一下是否有父加载器,若有交给父加载器加,否则调用 BootstrapClassLoader 加载。 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) { // 3. 如果第二步骤依然没有找到指定的类,那么调用当前类加载器的 findClass 方法来完成类加载。 // 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; } }
/** * This class is used by the system to launch the main application. Launcher类 */ publicclassLauncher { privatestaticURLStreamHandlerFactoryfactory=newFactory(); privatestaticLauncherlauncher=newLauncher(); // 1. Luncher 类加载后会从此静态变量调用到默认的构造方法 privatestaticStringbootClassPath= System.getProperty("sun.boot.class.path");
publicLauncher() { // Create the extension class loader ClassLoader extcl; try { extcl = ExtClassLoader.getExtClassLoader(); // 2. 扩展类加载器 } catch (IOException e) { thrownewInternalError( "Could not create extension class loader", e); }
// Now create the class loader to use to launch the application try { loader = AppClassLoader.getAppClassLoader(extcl); // 3. 应用类加载器(系统类加载器) } catch (IOException e) { thrownewInternalError( "Could not create application class loader", e); }
// Also set the context class loader for the primordial thread. // 4. 设置 ContextClassLoader 为应用类加载器(系统类加载器) Thread.currentThread().setContextClassLoader(loader);
// Finally, install a security manager if requested Strings= System.getProperty("java.security.manager"); if (s != null) { // init FileSystem machinery before SecurityManager installation sun.nio.fs.DefaultFileSystemProvider.create();
/* * The class loader used for loading installed extensions. 关于 ExtClassLoader */ staticclassExtClassLoaderextendsURLClassLoader {
// ...
privatestatic ExtClassLoader createExtClassLoader()throws IOException { try { // Prior implementations of this doPrivileged() block supplied // aa synthesized ACC via a call to the private method // ExtClassLoader.getContext().
/** * The class loader used for loading from java.class.path. 关于 AppClassLoader * runs in a restricted security context. */ staticclassAppClassLoaderextendsURLClassLoader {
// 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( newPrivilegedAction<AppClassLoader>() { public AppClassLoader run() { URL[] urls = (s == null) ? newURL[0] : pathToURLs(path); returnnewAppClassLoader(urls, extcl); } }); }
final URLClassPath ucp;
/* * Creates a new AppClassLoader */ AppClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent, factory); ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this); ucp.initLookupCache(this); }
/** * Override loadClass so we can checkPackageAccess. // 0. 重写 loadClass 方法:checkPackageAccess 之后调用 super.loadClass */ public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { inti= name.lastIndexOf('.'); if (i != -1) { SecurityManagersm= System.getSecurityManager(); if (sm != null) { sm.checkPackageAccess(name.substring(0, i)); } }
if (ucp.knownToNotExist(name)) { // The class of the given name is not found in the parent // class loader as well as its local URLClassPath. // Check if this class has already been defined dynamically; // if so, return the loaded class; otherwise, skip the parent // delegation and findClass. Class<?> c = findLoadedClass(name); if (c != null) { if (resolve) { resolveClass(c); } return c; } thrownewClassNotFoundException(name); }
return (super.loadClass(name, resolve)); }
// ... } }
5 自定义类加载器
自定义类加载器的目的:
隔离加载类:模块隔离,把类加载到不同的应用选中。比如 Tomcat 这类 Web 应用服务器,内部自定义了好几中类加载器,用于隔离 Web 应用服务器上的不同应用程序。