MDA/MDD/TDD/DDD/DDDDDDD
posts - 536, comments - 111, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

java类的加载

Posted on 2011-02-24 17:58 leekiang 阅读(368) 评论(0)  编辑  收藏 所属分类: java
打印Thread.currentThread().getContextClassLoader(),显示如下:
sun.misc.Launcher$AppClassLoader@19821f
这个加载器是系统类加载器。ClassLoader.getSystemResourceAsStream("com/config.xml")使用的就是系统类加载器定位资源的。


    //JDK1.6,java.lang.ClassLoader的loadClass(String name, boolean resolve)方法的源码
protected synchronized Class<?> loadClass(String name, boolean resolve)
    
throws ClassNotFoundException
    {
    
// First, check if the class has already been loaded
    Class c = findLoadedClass(name);
    
if (c == null) {
        
try {
        
if (parent != null) {
           //
如果parent不为null,则调用parent的loadClass进行加载 
            c = parent.loadClass(name, false);
        } 
else {
           //
parent为null,则调用BootstrapClassLoader进行加载
            c = findBootstrapClassOrNull(name);
        }
        } 
catch (ClassNotFoundException e) {
                
// ClassNotFoundException thrown if class not found
                
// from the non-null parent class loader
         }
       
if (c == null) {
            
// If still not found, then invoke findClass in order to find the class.
            //
如果仍然无法加载成功,则调用自身的findClass进行加载
            c = findClass(name);
        }
    }
    
if (resolve) {
        resolveClass(c);
    }
    
return c;
    }

java中共有三种类型的类加载器:
    1、引导(bootstrap)类加载器(用来加载java API类),例如加载java.lang.String类
    2、扩展类加载器(就是sun.misc.Launcher$ExtClassLoader,用来加载jre\lib\ext目录下的jar包)
    3、系统类加载器(就是sun.misc.Launcher$AppClassLoader,主要用来加载CLASSPATH设置目录中的Class)

创建一个URLClassLoader,发现其父加载器(parent,注意不是父类)的类型为sun.misc.Launcher$AppClassLoader,而sun.misc.Launcher$AppClassLoader和sun.misc.Launcher$ExtClassLoader的父类都是URLClassLoader。AppClassLoader的父加载器是ExtClassLoader,ExtClassLoader的父加载器为null,即bootstrap类加载器。

类加载有个双亲委托模式,
AppClassLoader的父加载器是ExtClassLoader ,ExtClassLoader 的父加载器是bootstrap classloader,bootstrap 是C++写的类加载器,会负责加载java核心类库,就是jre/lib/rt.jar
ExtClassLoader会加载扩展类库,就是jre/lib/ext下的库。

双亲委托模式就是子加载器会先委托父加载器加载,父加载器加载不了子加载器才加载,
这样做避免了重复加载,也加强了java的安全了,防止了恶意加载器去加载核心库。

String name = "com.domain.Account";
            
            URL url1 
= new URL("file:/D:/workspace/test/bin/");
            ClassLoader cl 
= new URLClassLoader(new URL[] { url1 });
            Class c1 
= cl.loadClass(name);
            
            URL url2 
= new URL("file:/D:/workspace/test/bin");
            ClassLoader cl2 
= new URLClassLoader(new URL[] { url2 });
            Class c2 
= cl2.loadClass(name);
            
            System.out.println(c1
==c2);//返回true,原因是都是用系统类加载器AppClassLoader加载的

注意:
1,在类A中使用Class.forName加载类B,那么加载类A的类加载器将会用于加载类B,这样两个类的类加载器是同一个。
2,Class.forName("")和classLoader.load("")的区别主要是前者会做初始化,后者不会。见jdk注释:A call to forName("X") causes the class named X to be initialized.  自己分别用两种方式装载一个带静态代码的类就知道了。jdbc需要通过Class.forName("")的方式来装载JDBC驱动程序(例如 Class.forName("com.mysql.jdbc.Driver"),之所以用Class.forName而没有用 ClassLoader.load(),就是因为需要JVM完成Driver的初始化工作,而不仅仅是装载),然后通过一个统一的工厂类 Java.sql.DriverManager来取得数据库连接,并执行各种操作。Class.forName("")不仅load class而且还保证resolve这个class,包括常量池解析,类初始化。。。这样JDBC驱动使用这个方法,才能保证类里的静态方法执行,一般驱动类的静态方法会向DriverManager注册自己,如果用classloader.load("")就不一定会resolve这个class,也就不能保证注册驱动类!
看了com.mysql.jdbc.Driver类的源码,静态代码就一句:java.sql.DriverManager.registerDriver(new com.mysql.jdbc.Driver())
3,

参考
1)java系统类加载器AppClassLoader之浅谈 http://blog.sina.com.cn/s/blog_4db6a3f101000do1.html
2)java类加载原理分析 http://gongmingwind.javaeye.com/blog/338366
3)解读ClassLoader http://www.javaeye.com/topic/83978
4)http://xyiyy.javaeye.com/blog/362107

Retrotranslator是一个Java字节码转换工具。它能够把用JDK5.0编译的Java Class转换成可运行在JVM1.4

只有注册用户登录后才能发表评论。


网站导航: