`
clq9761
  • 浏览: 587801 次
  • 性别: Icon_minigender_1
  • 来自: 福建
社区版块
存档分类
最新评论

Java类加载器入门应用

阅读更多

1、类加载器负责加载 Java 类的字节代码到 Java 虚拟机中。最初是为了满足 Java Applet的需要而开发出来的,
  Java Applet需要从远程下载Java类文件到浏览器中并执行。类加载器使得Java类可以被动态加载到Java虚拟机中并执行。


2、基本上所有的类加载器都是java.lang.ClassLoader类的一个实例,java.lang.ClassLoader类的基本职责
就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java类,
即java.lang.Class类的一个实例。除此之外,ClassLoader还负责加载Java应用所需的资源,
如图像文件和配置文件等。
ClassLoader中与加载类相关的方法如下:
(1)getParent() 返回该类加载器的父类加载器。 
(2)loadClass(String name) 加载名称为 name的类。
(3)findClass(String name) 查找名称为 name的类。
(4)findLoadedClass(String name) 查找名称为 name的已经被加载过的类。
(5)defineClass(String name, byte[] b, int off, int len) 把字节数组 b中的内容转换成 Java类。
(6)resolveClass(Class<?> c) 链接指定的 Java 类。

 

3、java虚拟机中可以安装多个类加载,系统默认三个主要类加载器,每个类负责加载特定位置的类:
(1)引导类加载器(BootStrp):
   它用来加载 Java的核心库,是用C++来实现的,并不继承自 java.lang.ClassLoader,
   主要加载目录JRE/lib/rt.jar
(2)扩展类加载器(ExtClassLoader):
    它用来加载 Java 的扩展库。主要加载目录JRE/lib/ext/*.jar。
(3)系统类加载器(AppClassLoader):
   它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类,主要加载目录CLASSPATH指定的所有jar或目录。
  Java 应用的类都是由它来完成加载的,可以通过 ClassLoader.getSystemClassLoader()来获取它。


4. 除了引导类加载器(BootStrp)之外,所有的类加载器都有一个父类加载器。可通过getParent()方法得到父类加载器。
   JDK 的实现对于父类加载器是引导类加载器(BootStrp)的情况,getParent()方法返回 null。例:

public class ClassLoaderTree {
	public static void main(String[] args) { 
        ClassLoader loader = ClassLoaderTree.class.getClassLoader(); 
        while (loader != null) { 
            System.out.println(loader.toString()); 
            loader = loader.getParent(); 
        } 
    } 
}

 输出结果如下:

sun.misc.Launcher$AppClassLoader@187c6c7
sun.misc.Launcher$ExtClassLoader@10b62c9

 

5、类加载器的委托机制
   当Java虚拟机要加载一个类时,首先当前线程的类加载器去加载线程中的第一个类,如果类A中引用了类B,
Java虚拟机将使用加载类A的加载器来加载类B.也可以直接使用loadClass()方法直接指定某个类加载器去加载某个类。
每个类加载器加载类时,会先委托给其上级类加载器,当所有上级类加载器没有加载到类时,回到发起者类加载器,
如果发起者类加载器还加载不了,则抛出ClassNotFoundException。

 

6、Java 虚拟机是如何判定两个 Java 类是相同的,Java 虚拟机不仅要看类的全名是否相同,
还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,
被不同的类加载器加载之后所得到的类,也是不同的。
为了保证Java核心库的类型安全。所有 Java 应用都至少需要引用 java.lang.Object类,
也就是说在运行的时候,java.lang.Object这个类需要被加载到 Java 虚拟机中。如果这个加载过程由Java应用
自己的类加载器来完成的话,很可能就存在多个版本的 java.lang.Object类,而且这些类之间是不兼容的。
通过代理模式,对于Java核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的
都是同一个版本的 Java 核心库的类,是互相兼容的。

 

7、Class.forName
Class.forName是一个静态方法,同样可以用来加载类。该方法有两种形式:

Class.forName(String name, boolean initialize, ClassLoader loader)

 第一种形式的参数 name表示的是类的全名;initialize表示是否初始化类;loader表示加载时使用的类加载器。

Class.forName(String className)

 第二种形式则相当于设置了参数 initialize的值为 true,loader的值为当前类的类加载器。

Class.forName的一个很常见的用法是在加载数据库驱动的时候。如

Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance()

 用来加载 Apache Derby 数据库的驱动。

 

8、编写自己的类加载器
一般来说,自己开发的类加载器只需要覆写 findClass(String name)方法即可。
java.lang.ClassLoader类的方法 loadClass()封装了前面提到的代理模式的实现,
该方法会首先调用 findLoadedClass()方法来检查该类是否已经被加载过;如果没有加载过的话,
会调用父类加载器的 loadClass()方法来尝试加载该类;如果父类加载器无法加载该类的话,
就调用 findClass()方法来查找该类。因此,为了保证类加载器都正确实现代理模式,在开发自己的类加载器时,
最好不要覆写 loadClass()方法,而是覆写 findClass()方法。例:

public class FileSystemClassLoader extends ClassLoader { 
    private String rootDir; 
    public FileSystemClassLoader(String rootDir) { 
        this.rootDir = rootDir; 
    } 
    protected Class<?> findClass(String name) throws ClassNotFoundException { 
        byte[] classData = getClassData(name); 
        if (classData == null) { 
            throw new ClassNotFoundException(); 
        } 
        else { 
            return defineClass(name, classData, 0, classData.length); 
        } 
    } 
    private byte[] getClassData(String className) { 
        String path = classNameToPath(className); 
        try { 
            InputStream ins = new FileInputStream(path); 
            ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
            int bufferSize = 4096; 
            byte[] buffer = new byte[bufferSize]; 
            int bytesNumRead = 0; 
            while ((bytesNumRead = ins.read(buffer)) != -1) { 
                baos.write(buffer, 0, bytesNumRead); 
            } 
            return baos.toByteArray(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
        return null; 
    } 
    private String classNameToPath(String className) { 
        return rootDir + File.separatorChar 
                + className.replace('.', File.separatorChar) + ".class"; 
    } 
}

 

8.Tomcat6的类加载器(从上至下)
(1)BootStrapClassLoader,Java的核心库,实际没有这个类
(2)ExtensionClassLoader,对于Sun JVM,是sun.misc.Launcher$ExtClassLoader,加载 Java 的扩展库。                     
(3) SystemClassLoader,对于Sun JVM,是sun.misc.Launcher$AppClassLoader,加载java的应用库。                     
(4) CommonClassLoader,对于Tomcat 6,是org.apache.catalina.loader.StandardClassLoader,
加载的类目录通过{tomcat}/conf/catalina.properties中的common.loader指定,
以SystemClassLoader为parent(目前默认定义是common.loader=${catalina.base}/lib,
${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar)
(5) CatalinaClassLoader,加载的类目录通过{tomcat}/conf/catalina.properties中server.loader指定,
 以CommonClassLoader为parent,如果server.loader配置为空,
 则ServerClassLoader 与CommonClassLoader是同一个(默认server.loader配置为空)
(6) SharedClassLoader:加载的类目录通过{tomcat}/conf/catalina.properties中share.loader指定,
 以CommonClassLoader为parent,如果server.loader配置为空,
 则CatalinaClassLoader 与CommonClassLoader是同一个(默认share.loader配置为空)
(7) WebappClassLoader:每个Context一个WebappClassLoader实例,
 负责加载context的/WEB-INF/lib和/WEB-INF/classes目录,
 context间的隔离就是通过不同的WebappClassLoader来做到的。
 由于类定义一旦加载就不可改变,因此要实现tomcat的context的reload功能,
 实际上是通过新建一个新的WebappClassLoader来做的,
 因此reload的做法实际上代价是很高昂的,需要注意的是,JVM内存的Perm区是只吃不拉的,
 抛弃掉的WebappClassLoader加载的类并不会被JVM释放,
 因此tomcat的reload功能如果应用定义的类比较多的话,reload几次就OutOfPermSpace异常了。
(8)JasperLoader:每个JSP一个JasperLoader实例,与WebappClassLoader做法类似,
JSP支持修改生效是通过丢弃旧的JasperLoader,建一个新的JasperLoader来做到的,
同样的,存在轻微的PermSpace的内存泄露的情况。

 

分享到:
评论

相关推荐

    经典JAVA.EE企业应用实战.基于WEBLOGIC_JBOSS的JSF_EJB3_JPA整合开发.pdf

    中文名: 经典Java EE企业应用实战--基于WebLogic/JBoss的JSF+EJB 3+JPA整合开发 原名: 经典Java EE企业应用实战--基于WebLogic/JBoss的JSF+EJB 3+JPA整合开发 作者: 李刚 资源格式: PDF 版本: 第一版 出版社: 电子...

    JAVA上百实例源码以及开源项目

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    JAVA上百实例源码以及开源项目源代码

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    java开源包11

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包6

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包9

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包4

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包101

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包5

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包8

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包10

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    疯狂JAVA讲义

    学生提问:构造器是创建Java对象的途径,是不是说构造器完全负责创建Java对象? 141 5.5.2 构造器的重载 142 学生提问:为什么要用this来调用另一个重载的构造器?我把另一个构造器里的代码复制、粘贴到这个构造器...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

    chapter15 反射与类加载器 499 15.1 运用反射 500 15.1.1 class与.class文档 500 15.1.2 使用class.forname() 502 15.1.3 从class获得信息 503 15.1.4 从class建立对象 506 15.1.5 操作对象方法与成员 ...

    java开源包3

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包1

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    JAVA基础课程讲义

    第一章 JAVA入门 10 计算机语言发展史 10 机器语言 10 汇编语言 10 高级语言 10 其他高级语言 11 JAVA发展简史 12 JAVA为什么能够流行? 13 JAVA各版本的含义 13 JAVA技术体系架构 14 JAVA的特性和优势 14 JAVA应用...

    Java语言基础下载

    类加载器 6 Windows环境变量 8 内容总结 13 独立实践 14 第二章: 面向对象概述 15 学习目标 15 面向对象(Object Oriented) 16 面向对象的主要特性 18 抽象(Abstraction) 18 封装(Encapsulation): 19 多态...

    java开源包2

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    Java服务器程序设计

    14.3.1 重用java类[/font] 14.3.2 创建自己的类[/font] 14.3.3 访问request和response对象[/font] 14.4 servlet初始化参数[/font] 14.5 pagecompile中使用的标记[/font] 14.6 小结[/font] [/font] 第4部分 java...

    java开源包7

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

Global site tag (gtag.js) - Google Analytics