Java 仮想マシン学習 - クラス ローダー (ClassLoader)

黄舟
リリース: 2017-02-17 10:31:06
オリジナル
1600 人が閲覧しました

クラスローダー

クラスローダー (ClassLoader) は、クラスのバイトコードを Java 仮想マシンにロードするために使用されます。一般に、Java 仮想マシンは次のように Java クラスを使用します。 Java ソース ファイルは、Javac を通過した後、Java バイトコード ファイル (.class ファイル) に変換されます。クラス ローダーは、Java バイトコードを読み取り、それを java.lang.Class クラスのインスタンスに変換する役割を果たします。このような各インスタンスは Java クラスを表します。たとえば、Java バイト コードはツールを通じて動的に生成されたり、ネットワークを通じてダウンロードされたりする場合があります。


クラスとクラスローダー

クラスローダーはクラスのロードアクションを実装するためにのみ使用されますが、Javaプログラムにおけるその役割はクラスロード段階に限定されるわけではありません。どのクラスでも、それをロードするクラスローダーとクラス自体は、Java 仮想世界でその一意性を確立する必要があります。より簡単に言うと、2 つのクラスが「等しい」かどうかを比較することは、2 つのクラスが同じクラス ローダーによってロードされた場合にのみ意味を持ちます。そうでない場合は、2 つのクラスが同じクラス ファイルからのものであっても、ロードされている限り意味があります。クラスローダーが異なる場合、2 つのクラスは等しくありません。ここでいう「等価性」には、equalメソッド、isAssignableFrom()、isInstance()メソッド、およびクラスを表すClassオブジェクトのinstanceキーワードで返される結果が含まれます。

クラスローダーの分類:



主に、ブートストラップクラスローダー、拡張クラスローダー、アプリケーションクラスローダー、ユーザー定義クラスローダーに分かれています。

ブートストラップ ClassLoader:

このクラス ローダーは C++ 言語で実装されており、ClassLoader のサブクラスではありません。主に、JAVA_HOME/jre/lib/rt.jar に保存されているすべてのクラス ファイル、または -Xbootclasspath パラメーターで指定されたパスにある rt.jar という名前のファイルをロードします。

拡張クラスローダー:

このローダーは、AVA_HOME / lib / ext ディレクトリのロードを担当する sun.misc.Launcher$ExtClassLoader によって実装されるか、または java.ext.dirs システム変数によって実装されます。指定されたディレクトリ内のすべてのライブラリパス。

アプリケーション クラスローダー:

このローダーは、クラスパスに対応する jar とディレクトリをロードする役割を担う sun.misc.Launcher$AppClassLoader によって実装されます。通常、これはプログラムのデフォルトのクラスローダーです。

カスタム クラス ローダー (ユーザー定義のクラス ローダー):

開発者は、ClassLoader 抽象クラスを継承し、独自に開発した ClassLoader に基づいて、クラスパス上のクラス以外のクラスをロードするために使用できます (インターネットからダウンロードした jar やバイナリ バイトコードなど)、クラス ファイルをロードする前に暗号化などの小さな操作を実行することもできます。

親委任モデル:

上図に示すクラスローダー間のこの階層関係を、クラスローダーの親委任モデルと呼びます。親委任モデルでは、トップレベルの起動クラス ローダーに加えて、他のすべてのクラス ローダーにも独自の親クラス ローダーが必要です。ここでのクラス ローダー間の親子関係は、通常、継承を通じて実装されず、代わりに、組み合わせ関係が親ローダーのコードを再利用するために使用されます。


りー


双亲委托的工作过程:如果一个类加载器收到了一个类加载请求,它首先不会自己去加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成加载请求(它管理的范围之中没有这个类)时,子加载器才会尝试着自己去加载。

使用双亲委托模型来组织类加载器之间的关系,有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,例如java.lang.Object存放在rt.jar之中,无论那个类加载器要加载这个类,最终都是委托给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类,相反,如果没有双亲委托模型,由各个类加载器去完成的话,如果用户自己写一个名为java.lang.Object的类,并放在classpath中,应用程序中可能会出现多个不同的Object类,java类型体系中最基本安全行为也就无法保证。

类加载器SPI:

java.lang.ClassLoader 类提供的几个关键方法:

loadClass: 此方法负责加载指定名字的类,首先会从已加载的类中去寻找,如果没有找到;从parent ClassLoader[ExtClassLoader]中加载;如果没有加载到,则从Bootstrap ClassLoader中尝试加载(findBootstrapClassOrNull方法), 如果还是加载失败,则抛出异常ClassNotFoundException, 在调用自己的findClass方法进行加载。如果要改变类的加载顺序可以覆盖此方法;如果加载顺序相同,则可以通过覆盖findClass方法来做特殊处理,例如:解密,固定路径寻找等。当通过整个寻找类的过程仍然未获取Class对象,则抛出ClassNotFoundException异常。

如果类需要resolve,在调用resolveClass进行链接。


    protected synchronized Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, check if the class has already been loaded
	Class c = findLoadedClass(name);
	if (c == null) {
	    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.
	        c = findClass(name);
	    }
	}
	if (resolve) {
	    resolveClass(c);
	}
	return c;
    }
ログイン後にコピー
findLoadedClass 此方法负责从当前ClassLoader实例对象的缓存中寻找已加载的类,调用的为native方法。



    protected final Class<?> findLoadedClass(String name) {
	if (!checkName(name))
	    return null;
	return findLoadedClass0(name);
    }

    private native final Class findLoadedClass0(String name);
ログイン後にコピー


findClass 此方法直接抛出ClassNotFoundException异常,因此要通过覆盖loadClass或此方法来以自定义的方式加载相应的类。


    protected Class<?> findClass(String name) throws ClassNotFoundException {
	throw new ClassNotFoundException(name);
    }
ログイン後にコピー


findSystemClass 此方法是从sun.misc.Launcher$AppClassLoader中寻找类,如果未找到,则继续从BootstrapClassLoader中寻找,如果仍然未找到,返回null


    protected final Class<?> findSystemClass(String name)
	throws ClassNotFoundException
    {
	ClassLoader system = getSystemClassLoader();
	if (system == null) {
	    if (!checkName(name))
		throw new ClassNotFoundException(name);
            Class cls = findBootstrapClass(name);
            if (cls == null) {
                throw new ClassNotFoundException(name);
            } 
	    return cls;
	}
	return system.loadClass(name);
    }
ログイン後にコピー


defineClass 此方法负责将二进制字节流转换为Class对象,这个方法对于自定义类加载器而言非常重要。如果二进制的字节码的格式不符合jvm class文件格式规范,则抛出ClassFormatError异常;如果生成的类名和二进制字节码不同,则抛出NoClassDefFoundError;如果加载的class是受保护的、采用不同签名的,或者类名是以java.开头的,则抛出SecurityException异常。


protected final Class<?> defineClass(String name, byte[] b, int off, int len,
					 ProtectionDomain protectionDomain)
	throws ClassFormatError
    {
         return defineClassCond(name, b, off, len, protectionDomain, true);
    }

    // Private method w/ an extra argument for skipping class verification
    private final Class<?> defineClassCond(String name,
                                           byte[] b, int off, int len,
                                           ProtectionDomain protectionDomain,
                                           boolean verify)
        throws ClassFormatError
    {
	protectionDomain = preDefineClass(name, protectionDomain);

	Class c = null;
        String source = defineClassSourceLocation(protectionDomain);

	try {
	    c = defineClass1(name, b, off, len, protectionDomain, source,
                             verify);
	} catch (ClassFormatError cfe) {
	    c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,
                                       source, verify);
	}

	postDefineClass(c, protectionDomain);
	return c;
    }
ログイン後にコピー
resolveClass 此方法负责完成Class对象的链接,如果链接过,则直接返回。


一般的な例外:

ClassNotFoundException この例外の理由は、現在の ClassLoader でクラスをロードするときにクラス ファイルが見つからなかったことです。

NoClassDefFoundError この例外は、ロードされたクラスが参照されているためです。さらに、クラスが存在しない場合、たとえば、A をロードしたいが、B が A から盗まれた場合、B が存在しない場合、または現在の ClassLoader が B をロードできない場合、この例外がスローされます。

LinkageError この例外は、カスタム ClassLoader の場合に発生する可能性が高くなります。主な理由は、このクラスがすでに ClassLoader にロードされており、繰り返しロードするとこの例外が発生することです。


上記は Java Virtual Machine Learning - ClassLoader の内容です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。


ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート