Java类加载器

类与类加载器

类由加载它的类加载器一起确定其在Java虚拟机的唯一性。
换句话说,类只有在同一个类加载器加载的前提下才能有可能比较相等,不同的类加载器加载的类必然是不相等的。

双亲委派模型

启动类加载器(Bootstrap Class Loader)

负责加载<JAVA_HOME>\lib目录下,或者被-Xbootclasspath参数指定的路径中存放的,而且是Java虚拟机能够识别的类库到虚拟机的内存。识别是按照文件名称识别,文件名不符合的类库即使在lib目录也不会被加载。
启动类加载器不能被Java程序直接引用。

扩展类加载器(Extension Class Loader)

负责加载<JAVA_HOME>\lib\ext目录中,或者别java.ext.dirs系统变量所指定的路径中的所有的类库。
JDK的开发团队允许用户将具有通用性的类库放在ext目录下以扩展Java SE的功能。
可以被Java程序直接引用。

应用类加载器(Application Class Loader)

负责加载用户类路径(ClassPath)上所有的类库
可以直接引用
如果引用程序没有定义过自己的类加载器,一般情况下引用类加载器就是默认加载器。

自定义类加载器
应用程序类加载器
自定义类加载器
扩展类加载器
启动类加载器

双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器。
通常使用组合关系来复用父加载器的代码。
工作过程:如果一个类加载器收到了类加载请求,首先把请求委派给父类加载器去完成,每个层次都是如此,所有的加载请求最终都到达定测的启动类加载器,只有当父加载器无法完成加载请求,子加载器才尝试自己完成加载。
越基础的类由越上层的类加载器进行加载。

protected synchronized Class<?> loadClass(String name, boolen resolve) throws ClassNotFoundException
{
   // 首先查找是否已经加载
   Class c = findLoadedClass(name);
   if (c == null){
      try {
      if (parent != null){
         // 父类加载器
         c = parent.loadClass(name, false);
      } else {
         // 启动类加载器
         c = findBootstrapClassOrNull(name);
      }
      } catch (ClassNotFoundException e) {
      }
      if (c == null ) {
          // 调用自定义类加载器,这里使用的不是loadClass而是findclass是有原因的
          c = findClass(name);
      } 
   }
   if (resolve) {
      resolveClass(c);
   }
   return c;
}

破坏双亲委派模型

  1. 双亲委派模型出现之前,已经存在的用户自定义类加载器
  2. 基础类型要调用用户代码,如JNDI、JDBC、JCE等
  3. 程序动态性:代码热替换、热部署

自定义类加载器

  1. 继承classloader
  2. 实现findClass()
  3. 如果要破坏双亲委派模型,就重载loadClass()方法,不再向父类委派,添加自己的逻辑

重点介绍一下OSGI

关键是自定义的类加载器机制,每个Bundle都有一个自己的类加载器,需要替换一个Bundle时,把Bundle连同类加载器一起换掉。类加载顺序如下:

  1. 将以java.*开头的类,委派给父类加载器加载。
  2. 否则,将委派列表名单内的类,委派给父类加载器加载。
  3. 否则,将Import列表中的类,委派给Export这个类的Bundle的类加载器加载。
  4. 否则,查找当前Bundle的ClassPath,使用自己的类加载器加载。
  5. 否则,查找类是否在自己的Fragment Bundle中,如果在,则委派给Fragment Bundle的类加载器加载。
  6. 否则,查找Dynamic Import列表的Bundle,委派给对应的Bundle的类加载器加载。
  7. 否则,类查找失败。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页