クラスローダーの細かい仕組みを触る
・JVM起動の際,java.*などの標準のクラス群をロードするクラスローダー
・JVMが起動後,mainメソッドを保持するアプリケーションプログラムをロードするクラスローダー
・その他,自分で勝手に作成したクラスローダー
最初のやつは「ブートストラップクラスローダー」で,次のが「システムクラスローダー」で,最後のヤツが単なるアプリケーションのクラスローダーです.
クラスローダーには親子関係があり,ブートストラップクラスローダーが一番の親,その子がシステムクラスローダー,我々が独自に作成するクラスローダーは,システムクラスローダーの子となります.もちろん,我々が独自に作成したクラスローダー間にも,親子関係を持たせることもできます.
ブートストラップクラスローダーは,JAVA_HOME/lib/*.jarなどに対してのクラスパスを保持しています.
システムクラスローダーは,javaコマンドの引数(または環境変数CLASSPATH)によって指定されたクラスパスを保持しています.
クラスがロードされる際,親から末端の子クラスローダーへ,順番にロード処理が行われます.
親クラスローダーが,既にクラスの参照を保持している場合,それが使用され,クラスファイルはロードされません.
何が言いたかったのかといいますと,JVM起動中にロード/アンロードしたいクラスは,アプリケーション起動時のクラスパスに含めてはならない,ということです.
アプリケーション起動時のクラスパスに含めるということは,システムクラスローダーがそれらをロードし,そして変更できなくなってしまうからです(JVM起動中にシステムクラスローダーを破棄することはできません).
★★
l Tomcat的container中需要一个自定义的loader,不能简单的直接使用系统的loader,因为所要运行的servlet是不可信任的。假如像使用之前章节一样使用系统中的loader,则该loader载入的servlet和其他类就能访问当前jvm实例中CLASSPATH环境变量下所有的类了,这非常不安全。servlet应该仅仅被允许从WEB-INF/classes及其子目录,和WEB-INF/lib下部署额lib中载入类。因此,servlet容器需要一个自定义的loader。每一个web一样(对应context容器)都有一个自定义的loader。在catalina中,loader组件要实现org.apache.catalina.Loader接口。
l 使用自定义loader的另一个原因是,可以支持class的自动重载。tomcat中的loader实现使用了另一个线程来检查servlet和相关类的时间戳,若是发生变化,则重新载入。为了支持class的重载,loader还要实现org.apache.catalina.loader.Reloader接口
l tomcat 中使用自定义类载入器的原因如下: (1)指定明确的类载入规则 (2)缓存已经载入的类 (3)预载入某个类,更方便使用。
l jvm使用三种loader:引导类载入器(bootstrap
class loader),扩展类载入器(extension class loader)和系统类载入器(system class
loader)。这三种有着父子继承关系(引导类载入位于最高层)。 引导类载入器(bootstrap
class loader)用于引导jvm。当使用java命令时,引导类载入器开始工作。引导类载入是使用本地方法实现的,因为它要负责载入启动jvm的类。此外,它还要负责载入java核心类,例如java.io和java.lang包下的类,它的搜索路径包括rt.jar和i18n.jar等包,具体查找哪些包依赖于jvm和操作系统的版本。
扩展类载入器(extension class loader)负责载入标准扩展目录下的类。这有利与程序开发,因为程序员只需要将jar包拷贝到扩展目录中,扩展类载入器会从这些jar包中查找需要的类。扩展目录依赖于jvm的具体实现。sun的jvm实现中标准扩展目录是“/jdk/jre/lib/ext”。 系统类载入器(system class loader)是默认的类载入器,从CLASSPATH中搜索需要的类。 那么,jvm到底使用哪个loader呢?为了尽可能的安全,jvm在这个问题上使用代理模型。每次需要载入一个新类时,首先使用系统类载入器。但是,该类并不会被立刻载入。相反,系统类载入器将这个任务代理给扩展类载入器执行,而扩展类载入器又将该任务代理给引导类载入器执行。因此,引导类载入器实际上是先载入这个类的。当引导类载入器无法载入这个类时,扩展类载入器尝试载入这个类,若扩展类载入器也载入失败,则系统类载入器尝试载入,若还是失败,抛出java.lang.ClassNotFoundException异常。