Java类加载器

3,806 views

Published on

关于java 类加载器(class loader)的介绍

Published in: Technology
1 Comment
5 Likes
Statistics
Notes
No Downloads
Views
Total views
3,806
On SlideShare
0
From Embeds
0
Number of Embeds
789
Actions
Shares
0
Downloads
104
Comments
1
Likes
5
Embeds 0
No embeds

No notes for slide

Java类加载器

  1. 1. Java类加载器 (class loader) 作者:Cheng Fu 作者:Cheng
  2. 2. 了解类加载器的好处 • 更加深入的了解Java语言的核心特性 • 有助于解决常见的ClassNotFoundException 和ClassDefNotFoundError • 满足特殊的加载类的需求 – 安全,保密 • 在JVM中创造隔离的环境,以及保护代码 • 面试或被面试中可能有用 2
  3. 3. Java类加载器简介 • Java中的类加载器(class loader)用来加载 Java字节代码到Java虚拟机(JVM) • 类加载器的引入被认为是Java语言惟一的重要 创新 • 类加载器从JDK 1.0就存在了,最初是为了满足 Applet的需要 3
  4. 4. 类加载器的必要性 • Java语言的口号 – 编写一次,到处运行 – 分发Java字节代码即可 • Java语言规范保证字节代码的兼容性 • 类加载器负责完成加载 编译器 类加载器 Java源代码 Java字节代码 Java虚拟机 (.java) (.class) 4
  5. 5. Java类 • Java中的类通过java.lang.Class来表示 • Java中的类加载器通过java.lang.ClassLoader 来表示 • 类加载器的作用就是从字节代码(byte数组) 中生成出来java.lang.Class的实例 5
  6. 6. 树状组织结构(1/2) • 类加载器的分类 – 系统提供 • 引导类加载器(bootstrap) – 加载Java核心库,原生代码实现 • 扩展类加载器(extensions) – 加载Java扩展库,在JVM的指定目录查找 • 系统类加载器(system) – 根据Java应用的类路径(classpath)来加载类 – 加载Java应用 – 开发人员提供 • 通过继承java.lang.ClassLoader类来实现 6
  7. 7. 树状组织结构(2/2) • 除了引导类加载器之外,所有的类加载器 都有一个父类加载器 – 通过getParent()方法可以获得父类加载器 • 通过这样的组织方式,系统中的类加载器 形成树状结构 • 对于开发人员编写的类加载器,其父类加 载器是加载这个类加载器的类加载器 – 注意:类加载器本身也是Java类,也是需要被 加载的 7
  8. 8. 8
  9. 9. 代理模式 • 类加载器在尝试自己去查找并加载某个类 之前,会先代理给其父类加载器 – 父类加载器会进一步代理给其父类加载器 • 只有在父类加载器无法加载的时候,才尝 试自己加载 9
  10. 10. 判断类是否相同 • JVM对类是否相同的定义是: – 类的全名相同 – 加载此类的类加载器相同 • 同样的字节代码,被不同的类加载器加载 之后,所得到的类是不同的! 10
  11. 11. 代理模式的作用 • 代理模式是为了保护Java核心库的类型安全 • 如果不用代理模式 – 所有的Java应用都至少需要引用java.lang.Object – 如果java.lang.Object由应用自己来加载 • JVM中存在多个版本的java.lang.Object类 • 它们之间是不兼容的! • 通过代理模式,Java核心库总是由引导类加 载器来负责加载 11
  12. 12. 初始和定义加载器 • 由于代理模式的存在,启动一个类的加载和最终 完成这个类的加载的,可能并不是同一个类加载 器 – 通过调用loadClass()方法来启动类的加载过程 • 初始加载器(initiating loader) – 通过调用defineClass()方法来完成类的定义 • 定义加载器(defining loader) • 得到java.lang.Class对象 • JVM判断类是否相同的时候使用的是定义加载器 • 一个类的定义加载器是它所引用的其它类的初始 加载器 12
  13. 13. 线程上下文类加载器 • 线程上下文类加载器(context class loader) 是为了解决代理模式的问题而引入的 – java.lang.Thread提供的getContextLoader()和 setContextLoader()方法 • Java提供的服务提供者接口(SPI) – Java核心库提供接口 • JDBC,JCE,JNDI,JAXP,JBI – 由第三方来提供实现 13
  14. 14. JAXP示例 • JAXP的接口定义在javax.xml.parsers包中, 包含在Java核心库中 • Apache Xerces提供了JAXP的实现,出现在类 路径(classpath)上 • SPI接口的代码需要使用加载具体的实现类 代理模式无法解决的问题! 14
  15. 15. 使用线程上下文类加载器 • Java应用运行的初始线程的上下文类加载器 正是系统类加载器 • SPI代码中通过线程上下文类加载器就可以 完成加载类路径上具体实现类的工作 15
  16. 16. 编写自己的类加载器 • 满足特定的加载类的需求 – 从某个网络位置下载Java字节代码 – 加密/解密 – 数字签名 • 继承自java.lang.ClassLoader类 16
  17. 17. java.lang.ClassLoader 方法 说明 loadClass(String name) 加载名称为name的类,返回java.lang.Class findClass(String name) 查找名称为name的类,返回java.lang.Class findLoadedClass(String name) 查找名称为name的已经被加载过的类,返回 java.lang.Class defineClass(String name, 把字节代码转换成Java类,返回java.lang.Class byte[] b, int off, int len) 自己的类加载器实现一般只需要覆写findClass()即可 代理模式的实现封装在findClass()方法中 17
  18. 18. Web应用中的类加载器 • Web应用中类加载器与一般Java应用不同 • 在Apache Tomcat中 – 每个Web应用对应自己的类加载器 – 它会首先尝试加载类,找不到再代理给父类加 载器 – 保证Web应用自己的类的优先级高于容器提供 的类 18
  19. 19. 处理Web应用依赖的类 • 每个应用自己使用的jar包,放在WEB- INF/lib目录下面 • 多个应用共享的jar包,放在Web容器的指 定目录下 19
  20. 20. OSGi • OSGi是Java的动态模块系统 • OSGi中的每个模块(bundle)可以依赖其它 模块或是为其它模块所用 – 导入:通过Import-Package声明 – 导出:通过Export-Package声明 • 每个模块由自己的类加载器 • 加载Java核心库的时候代理给父类加载器 20
  21. 21. 模块类加载器的代理模式 • 一个模块的类加载器在加载它所导入的类 的时候,会代理给导出此类的模块对应的 类加载器 代理类加载 模块A 模块B 加载 加载 继承自 类A 类B 21
  22. 22. 处理模块依赖的类 • 模块单独使用的jar包,放在模块中,通过 Bundle-Classpath声明 • 多个模块共享的jar包,单独创建一个新的 模块,把其中的Java类声明为导出的,其它 模块声明导入这些Java类 22
  23. 23. 隔离与保护 • 不同的类加载器为相同名称的类创建了额 外的名称空间 • 相同名称的类可以并存在JVM中 – 保护代码 – 版本控制 23
  24. 24. 参考资料 • Java类加载器(classloader)深入探讨 – http://www.ibm.com/developerworks/cn/java/j- lo-classloader/index.html • Java语言规范 – http://java.sun.com/docs/books/jls/ • OSGi规范 – http://www.osgi.org/Specifications/HomePage 24

×