JDK1.8源码笔记(7) ClassLoader

前言

A class loader is an object that is responsible for loading classes.

The class <tt>ClassLoader</tt> is an abstract class.
是抽象类,不能实例化,所以必须继承之后才可以使用。

Given the <a href="#name">binary name</a> of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class.
对于一个给定的类的二进制名,类加载器应该能够定位或产生一个类。

A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system.
一种常见的做法是把(binary name)转化为一个文件名,然后通过文件系统读入这么一个文件名的文件。

Every {@link Class <tt>Class</tt>} object contains a {@link Class#getClassLoader() reference} to the <tt>ClassLoader</tt> that defined it.
每一个Class对象都能通过getClassLoader方法引用到定义自己的那个ClassLoader。

<tt>Class</tt> objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime.
数组类的Class对象并不是由ClassLoader创建,而是按要求由Java运行环境自动创建。

* The class loader for an array class, as returned by {@link
* Class#getClassLoader()} is the same as the class loader for its element
* type; if the element type is a primitive type, then the array class has no
* class loader.
如果你尝试通过数组对象的getClassLoader获得ClassLoader的话,你会发现数组的ClassLoader和它的element type的ClassLoader相同(也就是说,虽然数组不是ClassLoader加载的,但是element type终究也还是ClassLoader加载的)。如果element type是基本类型,那么数组是没有类加载器的。

但是当我们尝试使用以下代码输出chars的类加载器的时候,发现输出的却是null,
Character[] chars = new Character[10];
System.out.println(chars.getClass().getClassLoader());

所以我们来看一下Class类中的getClassLoader方法:
@CallerSensitive
public ClassLoader getClassLoader() {
    ClassLoader cl = getClassLoader0();
    if (cl == null)
        return null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
    }
    return cl;
}
* Returns the class loader for the class.  Some implementations may use
* null to represent the bootstrap class loader. This method will return
* null in such implementations if this class was loaded by the bootstrap
* class loader.
可以看到这样一段话,有的实现中,如果该类是被bootstrap class loader加载的话,也会返回null。
If this object represents a primitive type or void, null is returned.
这和基本类型以及void类型的返回值相同,都是null。

在双亲委派模型中,bootstrap class loader就是处在根部的类加载器,负责加载一些最核心的类。
启动类加载器无法被Java程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给引导类加载器,那直接使用null代替即可。

This is because the bootstrap class loader is written in native code, not Java – so it doesn’t show up as a Java class. 

* Applications implement subclasses of <tt>ClassLoader</tt> in order to
* extend the manner in which the Java virtual machine dynamically loads
* classes.
应用程序通过执行ClassLoader的子类来扩展JVM动态加载类的功能。

Class loaders may typically be used by security managers to indicate security domains.

* The <tt>ClassLoader</tt> class uses a delegation model to search for
* classes and resources.  Each instance of <tt>ClassLoader</tt> has an
* associated parent class loader.  When requested to find a class or
* resource, a <tt>ClassLoader</tt> instance will delegate the search for the
* class or resource to its parent class loader before attempting to find the
* class or resource itself.  The virtual machine's built-in class loader,
* called the "bootstrap class loader", does not itself have a parent but may
* serve as the parent of a <tt>ClassLoader</tt> instance.
ClassLoader使用的是委派的方式去加载类和资源。每一个ClassLoader实例都和一个parent class loader相关联。当一个ClassLoader被要求去加载一个类的时候,在尝试自己去做之前,它会首先把这件事情交给它的parent class loader去做。VM内的bootstrap class loader是没有parent的。

* <p> Class loaders that support concurrent loading of classes are known as
* <em>parallel capable</em> class loaders and are required to register
* themselves at their class initialization time by invoking the
* {@link
* #registerAsParallelCapable <tt>ClassLoader.registerAsParallelCapable</tt>}
* method.
支持平行加载类的ClassLoaders被称为具有parallel capable。并且这些类加载器被要求在初始化的时候调用registerAsParallelCapable方法。

* Note that the <tt>ClassLoader</tt> class is registered as parallel
* capable by default. However, its subclasses still need to register themselves
* if they are parallel capable. <br>
ClassLoader是默认被注册为parallel capable。但是其子类仍需要注册才能称为parallel capable。

* In environments in which the delegation model is not strictly
* hierarchical, class loaders need to be parallel capable, otherwise class
* loading can lead to deadlocks because the loader lock is held for the
* duration of the class loading process (see {@link #loadClass
* <tt>loadClass</tt>} methods).
在委派模型并非严格分级的情况下,class loaders需要parallel capable,否则class loading会导致死锁。

* Normally, the Java virtual machine loads classes from the local file
* system in a platform-dependent manner.  For example, on UNIX systems, the
* virtual machine loads classes from the directory defined by the
* <tt>CLASSPATH</tt> environment variable.
通常来说,JVM从文件系统加载文件是平台相关的。

* <p> However, some classes may not originate from a file; they may originate
* from other sources, such as the network, or they could be constructed by an
* application.  The method {@link #defineClass(String, byte[], int, int)
* <tt>defineClass</tt>} converts an array of bytes into an instance of class
* <tt>Class</tt>. Instances of this newly defined class can be created using
* {@link Class#newInstance <tt>Class.newInstance</tt>}.
从本地文件加载类并不是唯一的途径,你也可以通过别的来源,比如说网络。甚至还可以由application来constructe。defineClass方法可以把一个字节数组转换为一个class实例。至于这个class类的实力化,可以用Class.newInstance方法。

* The methods and constructors of objects created by a class loader may
* reference other classes.  To determine the class(es) referred to, the Java
* virtual machine invokes the {@link #loadClass <tt>loadClass</tt>} method of
* the class loader that originally created the class.
这个被类加载器加载的类可能引用其他的对象。

* <p> Any class name provided as a {@link String} parameter to methods in
* <tt>ClassLoader</tt> must be a binary name as defined by
* <cite>The Java&trade; Language Specification</cite>.
*
* <p> Examples of valid class names include:
* <blockquote><pre>
*   "java.lang.String"
*   "javax.swing.JSpinner$DefaultEditor"
*   "java.security.KeyStore$Builder$FileBuilder$1"
*   "java.net.URLClassLoader$3$1"
* </pre></blockquote>
binary name似乎是类的全限定名。

* <p> The network class loader subclass must define the methods {@link
* #findClass <tt>findClass</tt>} and <tt>loadClassData</tt> to load a class
* from the network.  Once it has downloaded the bytes that make up the class,
* it should use the method {@link #defineClass <tt>defineClass</tt>} to
* create a class instance.
对于自定义一个类加载器的方法。

静态变量&静态方法

private static native void registerNatives();
static {
    registerNatives();
}
和Object类和Class类一样,都有这个registerNatives方法。

成员变量&成员方法

private final ClassLoader parent;
// The parent class loader for delegation
注意这个变量是final类型,这个变量用来记录用来委派的parent。

protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw new ClassNotFoundException(name);
}

* Finds the class with the specified <a href="#name">binary name</a>.
* This method should be overridden by class loader implementations that
* follow the delegation model for loading classes, and will be invoked by
* the {@link #loadClass <tt>loadClass</tt>} method after checking the
* parent class loader for the requested class.  The default implementation
* throws a <tt>ClassNotFoundException</tt>.
这个方法应该是由loadClass方法在其parent解决不了的时候调用。

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

* Loads the class with the specified <a href="#name">binary name</a>.  The
* default implementation of this method searches for classes in the
* following order:

*   <li><p> Invoke {@link #findLoadedClass(String)} to check if the class
*   has already been loaded.  </p></li>
*
*   <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method
*   on the parent class loader.  If the parent is <tt>null</tt> the class
*   loader built-in to the virtual machine is used, instead.  </p></li>
*
*   <li><p> Invoke the {@link #findClass(String)} method to find the
*   class.  </p></li>
加载一个类的大概流程如下,
首先需要获取锁,然后调用findLoadedClass方法判断欲加载的类是否已经被加载,如果未被加载,则把类加载工作委派给父类,如果成员变量parent为null,说明当前ClassLoader为BootstrapClassLoader,则自己会尝试加载这个类,如果成功则返回该Class对象的引用,失败的话就返回null,如果没有找到会抛出异常,接下来调用者本身会尝试加载这个类。

* <p> If the class was found using the above steps, and the
* <tt>resolve</tt> flag is true, this method will then invoke the {@link
* #resolveClass(Class)} method on the resulting <tt>Class</tt> object.
如果参数resolve的值为true,则会尝试去链接需要的类。

* <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
* #findClass(String)}, rather than this method.  </p>
建议用户覆写findClass(String)方法,而不是这个方法。

如何实现一个类加载器

https://blog.csdn.net/lalala_HFUT/article/details/99296615

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值