类加载器机制&双亲委派模型

类加载器机制

JAVA允许类从不同的地方被加载,只要得到的是二进制的class文件即可进行运行,所以需要一个管理加载类文件的工具,这个工具就是类加载器。类加载器负责加载类文件到JVM中。

JAVA中有多个系统自己定义的类加载器:

  1. 启动类加载器Bootstrap ClassLoader,负责加载\lib目录下核心库(rt.jar目录)
  2. 扩展类加载器Extension ClassLoader,负责加载\lib\ext
  3. 应用类加载器Application ClassLoader,负责加载用户编写的类目录的文件

类加载器之间是相互独立的,概念类似于命名空间,两个不同的类加载器中的同名类是不同的。

双亲委派模式

解决的问题

如果没有双亲委派模式,那么我们在自己的类中写一个Object类理论是可以的,因为和rt包中的不属于一个命名空间,但是问题在于这样会使得计算机不能了解应该加载哪个类而出现问题。双亲委派模式就是为了解决这种问题而出现的。

作用

双亲委派模式会使得多个类加载器间有一定的联系,一个用户编写的类需要加载的时候,理论上应该使用应用类加载器,但是根据双亲委派模式,他需要先让自己的父加载器看一下能否加载,如果父加载器能够加载则轮不到他。所以在加载类的时候会先追溯到启动类加载器,如果它不能处理这个类则逐级向下,得到处理为止,如果应用类加载器也加载失败,就会使用自定义加载器去尝试加载。都不能处理就报错。

优点

Java类伴随其类加载器具备了带有优先级的层次关系,确保了在各种加载环境的加载顺序。
保证了运行的安全性,防止不可信类扮演可信任的类。

局限性

1)因为具有层级的概念,父类加载器看不到子类加载器能够加载的文件。灵活性差。

SPI破坏

Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。

为什么需要破坏

JNDI服务的代码由启动类加载器去加载(rt.jar),但JNDI的目的就是对资源进行集中管理和查找,它需要调用独立厂商实现部署在应用程序的classpath下的JNDI接口提供者(SPI, Service Provider Interface)的代码,但启动类加载器不可能“认识”这些代码。

线程上下文类加载器

jdk1.2开始为我们提供了“线程上下文类加载器”,在代码运行的时候,我们可以从Thread中获取到线程上下文类加载器,这个加载器默认是当前的应用加载器,这样使得我们可以在核心服务中使用应用加载器。

热部署破坏/扩展

为什么需要破坏

想要实现热部署可以分以下三个步骤:

  1. 销毁该自定义ClassLoader
  2. 更新class类文件
  3. 创建新的ClassLoader去加载更新后的class类文件

这三步骤的实现必然需要一套类加载器的逻辑来实现。

OSGI类加载器模型

OSGI能够实现热插拔以及动态加载依靠的正是对双亲委派模型的扩展,具体逻辑如下。 但收到类加载请求时,OSGi会按照下面的顺序进行搜索:

  1. 将以java.*开头的类委派给父类加载器加载; 
  2. 否则,将委派类表名单内的类委派给父类加载器加载; 
  3. 否则,将Import列表中的类威派格Export这个类的Bundle的类加载器加载; 
  4. 否则,查找当前Bundle的ClassPath,使用自己的类加载器加载; 
  5. 否则,查找类是否在自己的Fragment Bundle中,如果在,则委派给Fragment Bundle的类加载器加载; 
  6. 否则,查找Dynamic Import列表的Bundle,委派给对应Bundle的类加载器加载; 
  7. 否则,类查找失败。 

上面的查找顺序只有前两条符合双亲委派模型,其余的类查找都是在平级的类加载器中进行的。

类加载器在tomcat中的应用



在Tomcat目录结构中,有3组目录(“/common/*”、“/server/*”和“/shared/*”)可以存放Java类库,另外还可以加上Web应用程序自身的目录“/WEB-INF/*”,一共4组,把Java类库放置在这些目录中的含义分别如下:

  1. 放置在/common目录中CommonClassLoader:类库可被Tomcat和所有的Web应用程序共同使用。
  2. 放置在/server目录中CatalinaClassLoader:类库可被Tomcat使用,对所有的Web应用程序都不可见。
  3. 放置在/shared目录中SharedClassLoader:类库可被所有的Web应用程序共同使用,但对Tomcat自己不可见。
  4. 放置在/WebApp/WEB-INF目录中WebappClassLoader:类库仅仅可以被此Web应用程序使用,对Tomcat和其他Web应用程序都不可见。

而JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的HotSwap功能。

你可能感兴趣的:(java,一周一篇Java概念)