java的本地类加载_JAVA类加载机制以及如何自定义类加载器

##从双亲委派说起

5531406651f4744b52c320017ebd8e31.png

启动(Bootstrap)类加载器:是用本地代码实现的类装入器,它负责将 /lib下面的类库加载到内存中(比如rt.jar)。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。

标准扩展(Extension)类加载器:是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将< Java_Runtime_Home >/lib/ext或者由系统变量 java.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。

系统(System)类加载器:是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。开发者可以直接使用系统类加载器。 除了以上列举的三种类加载器,还有一种比较特殊的类型 — 线程上下文类加载器。

双亲委派机制描述

某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

##Tomcat的类加载机制 本文主要以tomcat7为例说明类加载机制,大家也可以参考tomcat7的类加载机制的官方文档。Tomcat7总的ClassLoader结构如下图:

a9cac24375928609fdabd49dce9e2b7e.png

各个类加载器加载类的范围:

Bootstrap:包括java虚机机的基本类,以及$JAVA_HOME/jre/lib/ext下的类。

System:包括CLASSPATH环境变量的类,主要是$CATALINA_HOME/bin/bootstrap.jar和$CATALINA_BASE/bin/tomcat-juli.jar两个jar包

Common:包括tomcat的基本类,主要是$CATALINA_BASE/lib下的所有jar包

WebappX:应用相关类,保证应用之间的类隔离。先加载/WEB-INF/classes,再加载/WEB-INF/lib/*.jar

加载顺序默认如下

Bootstrap classes of your JVM

/WEB-INF/classes of your web application

/WEB-INF/lib/*.jar of your web application

System class loader classes (described above)

Common class loader classes (described above)

如果设置了,加载顺序如下:

Bootstrap classes of your JVM

System class loader classes (described above)

Common class loader classes (described above)

/WEB-INF/classes of your web application

/WEB-INF/lib/*.jar of your web application

##setContextClassLoader的理解 JDK的解释是这样的:

Sets the context ClassLoader for this Thread. The context ClassLoader can be set when a thread is created, and allows the creator of the thread to provide the appropriate class loader, through , to code running in the thread when loading classes and resources.

**并不是给线程设置了ContextClassLoader,这个线程下加载的类就都使用该ContextClassLoader。**ContextClassLoader的用途是提供一个途径,使得线程运行时可以随时获得指定的ContextClassLoader进行类的加载,通过这个这种方式可以避开双亲委派模型,最典型的应用是JDBC、JNDI。

##自定义的ClassLoader 自定义的ClassLoader通过继承ClassLoader来实现,也可以使用URLClassLoader更简单。如果需要改写类的加载过程最好覆盖findClass()而不是loadClass(),loadClass()是为了保持jdk1.2之前的兼容。使用findClass()能保证不会违背双亲委派模式。

如何使用自定义的ClassLoader new出对象呢?前面说过的setContextClassLoader是不对的,必须用自定义的ClassLoader,通过反射实例化一个初始类,由该初始类加载的其他类就都会使用自定义的ClassLoader了。可以分析一下tomcat的代码:

Class> startupClass =

catalinaLoader.loadClass

("org.apache.catalina.startup.Catalina");

Object startupInstance = startupClass.newInstance();

通过反射机制调用startupInstance的方法,之后的类就会都有自定义的ClassLoader加载,当然有个前提就是不能违背双亲委派模型——自定义的ClassLoader加载的类在父ClassLoader加载的类中不存在。为什么要这么做?类加载的时候有一个规律,被加载类使用调用者所用的ClassLoader进行类的加载。可以通过Class.forName()的代码得到这个结论:

public static Class> forName(String className)

throws ClassNotFoundException {

Class> caller = Reflection.getCallerClass();

return forName0(className, true, ClassLoader.getClassLoader(caller), caller);

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值