java 类加载机制

来源:互联网 发布:hp网络打印机设置ip 编辑:程序博客网 时间:2024/06/03 19:59

背景

   类加载可以将一个用全限定名来描述的类加载到虚拟机中,了解类加载机制可以帮助更快的解决一些日常的jar包冲突等问题。

双亲委派模型

  在java中,这些类加载器都由java语言实现,并且都继承自java.lang.ClassLoader。
  
  绝大部分java程序都会使用到下面三种类加载器:

  1. 启动类加载器:加载\lib目录下的jar包
  2. 扩展类加载器用来加载\lib\ext目录下jar
  3. 应用程序类加载器:负责加载用户类加载器路径上所指定的类库。

下图展示了三个类加载器的关系:

这里写代码片

Java采用的是双亲委派模型,即当需要加载一个类的时候,优先由父类加载器加载。这样可以保障的是如果用户自己定义了一个基础类的class,系统则会优先加载系统自带的class,一定程度上保障了安全性。那么除了双亲委派模型,难道没有别的模型,这种模型有什么局限性呢?其实对于java而言,如果A类中引用了B,那么默认会使用A类的加载器去加载B,那么带来一个问题即,如果A是系统类,由启动类加载器加载,而B则是我们应用程序类,那么这个时候双亲委派模型就无法满足我们的要求,因为启动类加载器无法正常加载自定义类。类似的例子如jdbc,DriverManager是系统类加载器加载的,但是它可能引用到的是我们mysql jdbc。这个时候就用到了一个类ContextClassLoader。

ContextClassLoader

如上文所述,系统的类加载器无法加载应用程序的类,我们可以通过当前线程的上下文加载器,将我们的应用程序加载器或者自定义类加载器设置成上下文加载器,当需要加载用户自定义类的时候,从上下文中获取类加载器即可获取。一个非常典型的例子就是tomcat的类加载机制。一个tomcat可能会包含很多应用,需要解决两个问题:
  1. tomcat自己的类,如果每个应用都复制一份的话,成本太高,因此tomcat自带类需要共享。
  2. 每个应用自带的类需要隔离,例如两个应用依赖的是spring版本不同,那么如果共享的话,会导致类冲突。

      下图是tomcat的类加载器:
    这里写图片描述

    CommonClassLoader、CatalinaClassLoader、SharedClassLoader和WebappClassLoader分别加载/common/*、

/server/、/shared/和/WebApp/WEB-INF/*的类,而CommonClassLoader的父加载器是java里面应用程序类加载器,在tomcat中CatalinaClassLoader、SharedClassLoader默认是和CommonClassLoader一个实例,CommonClassLoader加载三个系统目录下的类,而对于WebAppClassLoader,通过自定义类加载,并将其设置成线程上下文类加载器,从而实现类隔离。

总结:

  本文描述了java的类加载器机制,java类加载器机制主要是以双亲委派为主,在特定的场景下由于类隔离等原因,会破坏掉双亲委派,实现更大的灵活性。

0 0
原创粉丝点击