java中所有的类都是通过classloader加载的,classloader可以为java程序提供很好的动态特性,深入了解非常有必要。

1)classloader的分类

从上图看到classloader默认有3类,

BootstrapLoader
ExtClassLoader
AppClassLoader
同时你也可以定制自己的classloader

这些classloader分别加载不同路径下的类,路径如上图所示

2)父子关系的含义

如上图所示,这几个classloader存在父子关系
下层的classloader会委托上层的classloader加载某个类,如果上层找不到才轮到自己,也就是说下层classloader
能看到上层的类,但反过来不是这样,这也成为委托模型

3)父子关系是如何确定的?
默认情况下,BootstrapLoader,ExtClassLoader,AppClassLoader的父子关系是固定,如果你定义了自己的classloader,也许会有多级,那么自定义classloader的初始化的所在的类就默认成为parent
比如你会在AppClassLoader中定义类加载器,此时你定义的classloader的parent就是AppClassLoader

4)类与它所依赖的类的classloader机制
如果一个类是由某个classloader加载,那么这个类依赖的类(非显式的通过某个classloader加载)必须也由该classloader或其父classloader加载,无视子classloader
比如A类依赖B类,你在A类的某个方法中new B(); 不可能A类由 BootstrapLoader加载,而B 类由 AppClassLoader
或者一个A类实现了C 接口,不可能A类由 BootstrapLoader加载,而C接口由 AppClassLoader

5)位于父classloader中的类真的无法依赖位于子classloader中的类码?

通过显式的使用classloader!

5.1)通过URLClassLoader.load
比如在位于AppClassLoader中的Test类中的main方法成功依赖了位于子classloader中Word类
URL u = new URL("file:/tmp/");
URLClassLoader ucl = new URLClassLoader(new URL[] { u });
Class c = ucl.loadClass("org.toy.classloader.Word");
Assembly asm = (Assembly) c.newInstance();
c.start();

5.2)通过thread.getContextClassloader

thread.getContextClassloader默认返回AppClassLoader,除非你显式setContextClassloader

上面的用法不过优雅,让我们从jdk jdbc的源码中学点经验

看看java是如何加载jdbc driver的
view plaincopy to clipboardprint?
java.sql.DriverManager.getConnection---->  
java.sql.DriverManager.initialize---->  
java.sql.DriverManager.loadInitialDrivers---->  
java.security.AccessController.doPrivileged---->  
java.sql.DriverService.run---->  
sun.misc.Service.providers(java.sql.Driver.class)---->  
sun.misc.Service$LazyIterator()---->  
sun.misc.Service$LazyIterator.next---->  
Class.forName(cn, true, loader).newInstance(); 
java.sql.DriverManager.getConnection---->
java.sql.DriverManager.initialize---->
java.sql.DriverManager.loadInitialDrivers---->
java.security.AccessController.doPrivileged---->
java.sql.DriverService.run---->
sun.misc.Service.providers(java.sql.Driver.class)---->
sun.misc.Service$LazyIterator()---->
sun.misc.Service$LazyIterator.next---->
Class.forName(cn, true, loader).newInstance();

上面的loader就是通过 Thread.currentThread().getContextClassLoader()传递的,在加载之前,上面的next方法,通过classloader.getResources("META-INF/services/java.sql.Driver") 发现文件
比如
jar:file:/home/pwlazy/dev/jdk1.6.0_17/jre/lib/resources.jar!/META-INF/services/java.sql.Driver
jar:file:/home/pwlazy/.m2/repository/mysql/mysql-connector-java/5.1.10/mysql-connector-java-5.1.10.jar!/META-INF/services/java.sql.Driver
这两个jar包都含有这个文件,文件的内容就是驱动的类名
比如上面两个文件分别对应类名sun.jdbc.odbc.JdbcOdbcDriver和 com.mysql.jdbc.Driver

于是classloader开始加载驱动类,
但最后开始开始连接数据库的时候,
会通过下面的方法来验证调用者是否有权限加载驱动类。
view plaincopy to clipboardprint?
private static Class getCallerClass(ClassLoader callerClassLoader,  
                    String driverClassName) {  
    Class callerC = null;  
    try {  
        callerC = Class.forName(driverClassName, true, callerClassLoader);  
    }  
    catch (Exception ex) {  
        callerC = null;           // being very careful  
    }  
    return callerC;  
    } 
private static Class getCallerClass(ClassLoader callerClassLoader,
                    String driverClassName) {
    Class callerC = null;
    try {
        callerC = Class.forName(driverClassName, true, callerClassLoader);
    }
    catch (Exception ex) {
        callerC = null;           // being very careful
    }
    return callerC;
    }

做个小实验:
如果把调用类放在ExtClassLoader下,那么com.mysql.jdbc.Driver最终是无法调用的,因为调用类处于ExtClassLoader,而com.mysql.jdbc.Driver处于AppClassLoader,所以验证无法通过
但sun.jdbc.odbc.JdbcOdbcDrive是可以,因为它是BootstrapLoader加载的

从上面的分析,我们可以嗅到一个有趣的模式,某个框架制定某个API,而这些api的实现是有其他供应商来提供,为了能让框架类(处于较高层次的classloader)使用api的实现(处于较低层次的classloader)
通过thread.getContextClassloader是来传递classloader(有时候需要thread.setContextClassloader设置好api实现的classloader),用此classloader.getResources找出所有的api实现的具体类名,再用classloader加载之,此时框架都不需要知道api的实现类的类名就能加载之,程序显示了良好的动态性和可扩展性。

总之classloader默认的委托模型使得处于上层的classloader中的类无法访问处于下层classloader中的类,这带来了安全性的同时也失去了灵活性,幸好 可以使用Thread.currentThread().getContextClassLoader()

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/pwlazy/archive/2009/12/25/5072468.aspx

深入浅出classloader相关推荐

  1. 深入浅出ClassLoader(译)

    该文章来自阿里巴巴技术协会(ATA)精选集 你真的了解ClassLoader吗? 这篇文章翻译自zeroturnaround.com的 Do You Really Get Classloaders?  ...

  2. 深入浅出Android系统启动流程

    转载请标明出处:[顾林海的博客] 本篇文章已授权微信公众号 顾林海 独家发布 init进程启动过程 init进程概述 Android系统基于Linux,init进程是Android系统中用户空间的第一 ...

  3. [转载] 深入了解Java ClassLoader、Bytecode 、ASM、cglib

    转载自http://www.iteye.com/topic/98178 一.Java ClassLoader 1,什么是ClassLoader  与 C 或 C++ 编写的程序不同,Java 程序并不 ...

  4. java 字节码增强原理_深入浅出Java探针技术1--基于java agent的字节码增强案例

    Java agent又叫做Java 探针,本文将从以下四个问题出发来深入浅出了解下Java agent 一.什么是java agent? Java agent是在JDK1.5引入的,是一种可以动态修改 ...

  5. Java高级篇——深入浅出Java类加载机制

    转载自 Java高级篇--深入浅出Java类加载机制 类加载器 简单讲,类加载器ClassLoader的功能就是负责将class文件加载到jvm内存. 类加载器分类 从虚拟机层面讲分为两大类型的类加载 ...

  6. 深入浅出单实例Singleton设计模式

    深入浅出单实例Singleton设计模式 陈皓 前序 单实例Singleton设计模式可能是被讨论和使用的最广泛的一个设计模式了,这可能也是面试中问得最多的一个设计模式了.这个设计模式主要目的是想在整 ...

  7. java探针 字节码增强_深入浅出Java探针技术1--基于java agent的字节码增强案例

    Java agent又叫做Java 探针,本文将从以下四个问题出发来深入浅出了解下Java agent 一.什么是java agent? Java agent是在JDK1.5引入的,是一种可以动态修改 ...

  8. Python --深入浅出Apriori关联分析算法(二) Apriori关联规则实战

    上一篇我们讲了关联分析的几个概念,支持度,置信度,提升度.以及如何利用Apriori算法高效地根据物品的支持度找出所有物品的频繁项集. Python --深入浅出Apriori关联分析算法(一) 这次 ...

  9. JVM系列(之ClassLoader)

    Class Loader Java运作流程 内部class loader bootstrap class loader --引导类加载器,它负责加载Java的核心类[java.* ](如classpa ...

最新文章

  1. Back-propagation, an introduction
  2. 【发布】温度监测报警器v1.1a内测版!
  3. 设计模式解析笔记之Adapter模式
  4. Java无处不在:使用DukeScript在任何地方运行一次编写
  5. Error running ‘Tomcat‘: Unable to open debugger port (127.0.0.1:2148): java.net.SocketExceptio
  6. 04-Fibonacci
  7. linux contos升级内核,CentOS7升级内核方法
  8. SVD decomposition and polar decomposition
  9. mahout AbstractJDBCModel log
  10. linux中执行命令权限不够怎样处理
  11. 4个GIF免费压缩工具,尽量保留画质的前提下一键快速压缩!
  12. 数据结构二叉树学习1-前序序列创建二叉树
  13. linux终端ppt,[转]TPP:linux终端下的ppt
  14. 微信小程序自定义头部导航栏
  15. 源码编译安装LAMP
  16. 认识USB、Type-C、闪电、雷电接口
  17. 那个职员建议他们去计算机博物馆英语,新目标英语九年级Unit 3 Section B录音(音频+文本+翻译)...
  18. Cay S.Horstmann:从Java新特性看Java的未来
  19. STM32F1系列之常用外设说明
  20. 如何在网页端登录企业邮箱修改密码?

热门文章

  1. java float 加法_JAVA 实现精确的加减乘除运算
  2. Memcache与Memcached的区别
  3. Note:类(Class)
  4. mysql server uuids_slave have equal MySQL Server UUIDs原因及解决
  5. easyexcel导入时读不到数据_EasyExcel简单使用--导入excel数据
  6. java retentionpolicy_Java注解之如何利用RetentionPolicy.SOURCE生存周期
  7. 用php文件创建表,使用PHP创建单个文件上传表单的最佳方式是什么?
  8. vscode 新建php模板,使用VSCode快速创建vue文件模版的方法介绍
  9. Math.round(11.5)等于多少? Math.round(-11.5)等于多少?
  10. 将字符串下标为奇数的字符按ASCII码大小递增排序,并将排序后下标为奇数的字符取出