`
生死格斗
  • 浏览: 127686 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java虚拟机(JVM)的动态类加载(Class Loading)(转)

阅读更多
1.介绍

              Class Loaders是动态加载Java类与Resource的一种机制。它支持Laziness,type-safe linkage,user-defined extensibility和multiple communicating namespaces这4种特性。

l         Lazy loading:Class只有在需要的时候才加载。这样减少了内存使用量,能提高系统反映速度;

l         Type-safe linkage:动态类加载不会破坏JVM的类型安全;

l         User-definable class loading policy:开发者可以自定义的类加载器,控制动态类加载过程;

l         Multiple namespaces:JVM允许使用不同的类加载器加载相同的Class名称,但不同内容的类。

Class Loaders早在JDK1.0时就已存在,最开始的目的是使HotJava浏览器能加载Applet。从那以后,动态类加载机制被广泛应用到其他方面,例如web application server中Servlets的加载。class loader在JDK 1.0,1.1版本存在的缺陷,已经在JDK 1.2解决,其缺陷主要是编写不正确的Class Loader会造成类型安全问题。

2.Class Loaders

Class Loader的目的是动态加载Java类和Resource。Java类是平台无关的,标准的,具有规范二进制文件格式的。class文件有编译器生成,可以被任何一中JVM加载。Java类的表现形式不仅只有.class文件,还可以为内存buffer,或是网络数据流。

JVM执行class文件内的Byte code。但是Byte code不是class文件的全部内容,class文件内还包含符号表,表示类,属性和方法名,以及类内引用到其他类,属性,和方法名。例如下面的类

       class C{

                     void f(){

                                   D d=new D();

                     }

       }

类文件内类C引用D。为了能让JVM知道D类是什么,JVM必须要先load D的class file并创建D class对象。

JVM使用类加载器加载类文件,并创建Class对象。类加载器都是ClassLoader的子类实例。ClassLoader.loadClass方法通过获得一个类名,返回一个Class对象,表示该类的类型。上面的代码里,假设C被类加载器L加载,则L是C的加载器。JVM将使用L加载所有被C引用到的其他Java类。

如果D还没有被加载,L将加载D:

       L.loadClass(“D”)

当D已经被加载,JVM就可以创建D的一个对象实例。

一个Java应用程序可以使用不同类型的类加载器。例如Web Application Server中,Servlet的加载使用开发商自定义的类加载器,java.lang.String在使用JVM系统加载器,Bootstrap Class Loader,开发商定义的其他类则由AppClassLoader加载。在JVM里由类名和类加载器区别不同的Java类型。因此,JVM允许我们使用不同的加载器加载相同namespace的java类,而实际上这些相同namespace的java类可以是完全不同的类。这种机制可以保证JDK自带的java.lang.String是唯一的。

ClassLoader子类需要重载loadClass方法以实现用户自己的类加载方式,下面是自定义一个类加载器例子:

package org.colimas.webapp;



import java.io.File;

import java.io.IOException;

import java.net.URL;

import java.net.URLClassLoader;

import java.util.StringTokenizer;





/**

*类加载器加载Servlet,URLClassLoader是ClassLoader的一个子类,可以通过URL加载Java类或其它资源。

* @author 趙磊

*

*/

public class WebAppClassLoader extends URLClassLoader {

      

    private ClassLoader _parent;

   

       public WebAppClassLoader(ClassLoader parent) {

                     super(new URL[0], parent);

                     _parent=parent;

        if (parent==null)

            throw new IllegalArgumentException("no parent classloader!");

       }

       //追加一个Class Path。

       public void addClassPath(String classPath) throws IOException{

        if (classPath == null)

            return;

        StringTokenizer tokenizer= new StringTokenizer(classPath, ",;");

        while (tokenizer.hasMoreTokens())

        {       

               URL url=null;

            File file=new File(tokenizer.nextToken()).getCanonicalFile();

            url=file.toURI().toURL();

            addURL(url);

        }

       }

       //加载类

       public synchronized Class loadClass(String name)

                     throws ClassNotFoundException {



                     return loadClass(name,false);

       }



       protected synchronized Class loadClass(String name, boolean resolve)

                     throws ClassNotFoundException {

              

                     Class c= findLoadedClass(name);

              

                     ClassNotFoundException ex= null;

              

              

                     if (c == null && _parent!=null ){

                  

                                   try{

              

                                                 c= _parent.loadClass(name);

                  

                                   }catch (ClassNotFoundException e){

                       ex= e;

                  

                                   }

              

                     }



                     if (c == null){

                  

                                   try{

                                                 c= this.findSystemClass(name);

                  

                                   }catch (ClassNotFoundException e){

                                                

                       ex= e;

                  

                                   }

              

                     }

              

                     if (c == null)

          

                                   throw ex;



                    

              

                     if (resolve)

                  

                                   resolveClass(c);

              

                     return c;

       }

}

loadClass方法中使用findLoadedClass方法检查类是否已经被加载。该方法是Native方法,实现在JVM的ClassLoader.c文件内的Java_java_lang_ClassLoader_findLoadedClass函数。如果返回为null,则表示类还没有被加载,于是在其Parent类加载器重寻找_parent.loadClass,如果仍然返回null,则要在系统中查找,findSystemClass,如果仍然没有,则抛出异常。我们要确保多线程在同一时间只能加载一次,因此需要synchronized。

通常我们需要动态更新一个Class。例如一个Servlet实现发生变化时,我们希望不是重启服务器而是Reload。下面的类ServletWrapper提供了一个Servlet Reload的实现方法:

package org.colimas.webapp;



import javax.servlet.Servlet;

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;



/**

* @author 趙磊

*

*/

public class ServletWrapper {

   

       private Servlet theServlet;

    private Class servletClass;

    private ServletConfig config;

    private String _servletname;

   

    public ServletWrapper(ServletConfig config){

                  this.config=config;

    }

   

    public Servlet getServlet() throws ServletException{

               synchronized (this) {



                       destroy();

                      

                       try {

                                    

                                     WebAppClassLoader loader=new WebAppClassLoader(this.getClass().getClassLoader());

                                     String name=getServletName();

                           servletClass = loader.loadClass(name);

                          

                           theServlet = (Servlet) servletClass.newInstance();

                          

                          

                       } catch( ClassNotFoundException ex1 ) {

                         

                       } catch( InstantiationException ex ) {

                          

                       }catch(IllegalAccessException ex2){

                                    

                       }

                      

                       theServlet.init(config);

                   }

               return theServlet;          

    }

    public void destroy() {

        if (theServlet != null) {

            theServlet.destroy();

        }

    }   

   

    protected String getServletName(){

                  return _servletname;

    }

}

getServlet()获得一个Servlet对象。首先创建一个新的Servlet类加载器。loader.loadClass加载最新的Servlet,servletClass.newInstance()实例化新的Servlet对象,并theServlet.init(config);让它运行起来。这种方法只有在不改变Servlet的接口时有效的。如果你要加载的类不实现任何接口,那么就不能在ServletWrapper直接使用该类名。而是定义为Object theServlet,并且theServlet = servletClass.newInstance();,而theServlet.init(config);也不得不改写为:

Method m= servletClass.getMethod(“init”,…);

m.invoke(theServlet,…);



3. Type-safe Linkage和Namespace一致性



JVM使用loaded class cache保存class名和加载该class的类加载器。当JVM通过loadClass获得class之后,它执行以下操作:

l         检查传给loadClass的类名是否和真实类名一致;

l         如果一致,则保存到loaded class cache里。

ClassLoader.findLoadedClass就是在loaded class cache查找class是否存在的。

为了保证Type-safe,Sun公司做了很多工作,目前也有不止一个解决方案。例如,增加约束规则(Contraint Rule)等。
分享到:
评论

相关推荐

    jvm 加载class文件

    Java作为一种动态性极强的解释型编程语言,在程序运行时,Java虚拟机(JVM)负责将编译生成的`.class`文件加载到内存中进行执行。在Java环境中,每个类(Class)以及接口(Interface)都会对应一个`.class`文件,...

    Java虚拟机----类的加载过程.docx

    Java虚拟机(JVM)的类加载过程是Java程序运行的基础,它涉及到类加载器、类的生命周期和一系列复杂的步骤。在这个过程中,类加载器主要任务是根据类的全限定名加载二进制字节流并转化为`java.lang.Class`对象。整个...

    JVM内幕:java虚拟机详解

    8. **更快的类加载(Faster Class Loading)** - 快速类加载是指通过缓存机制来加速类的加载过程,避免重复加载相同的类。 9. **运行时常量池(Runtime Constant Pool)** - 运行时常量池包含了类或接口在编译期产生...

    Java虚拟机工作原理详解

    类加载器是 Java 虚拟机中的一种机制,负责将类文件从文件系统加载到 JVM 的内存区域中。类加载器被组织成一种层级结构关系,也就是父子关系,其中 Bootstrap 是所有类加载器的父亲。 * Bootstrap class loader:...

    Java虚拟机和Java程序的生命周期?

    1. **加载(Loading)**:类加载器通过特定的途径(如文件系统、网络等)找到类的二进制形式,并将其转化为字节流,再将这些字节流转化为Class对象。 2. **验证(Verification)**:确保输入的Class文件符合当前...

    springboot+java类热加载

    `ClassUtil.java`可能包含了一些辅助方法,用于在运行时编译修改后的Java源码,然后由类加载器加载到JVM中。Java的`javac`工具或第三方库如Apache Ant或Maven的Compiler插件可以用于此目的。 **自动引用依赖**:在...

    Java虚拟机(JVM)面试题 51道.pdf

    Java虚拟机(JVM)是Java程序的核心组成部分,它为Java提供了一个跨平台的运行环境。JVM的主要功能是解析并执行Java字节码,确保Java程序能够在不同的操作系统上无缝运行,这得益于Java的“一次编写,到处运行”...

    Java类加载原理解析

    了解类加载机制对于解决这类问题至关重要,同时也有助于深入理解Java虚拟机(JVM)的工作原理。 Java 类加载机制主要由类加载器完成。JVM内置了三种预定义的类加载器: 1. **启动类加载器(Bootstrap ClassLoader...

    深入java虚拟机(七)深入源码看java类加载器ClassLoader 1

    它负责将类的字节码加载到Java虚拟机(JVM)中,使得程序能够运行。ClassLoader是一个抽象类,它的主要任务是根据类的全限定名(即包名加类名)来查找或生成相应的字节码,并从中定义出Java类。除此之外,...

    北京圣思园深入Java虚拟机

    - 虽然JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,但如果在这个过程中遇到`.class`文件缺失或存在错误,则类加载器必须在程序首次主动使用该类时才报告错误(例如`LinkageError`)。 5. **类的...

    深入理解Java虚拟机笔记(带目录).docx

    Java 虚拟机(JVM)是 Java 语言的运行环境,它负责解释和执行 Java 字节码。下面是 Java 虚拟机相关的知识点: 虚拟机内存结构 Java 虚拟机的内存结构主要包括以下几个部分: * 方法区(Method Area):用于存储...

    Java虚拟机(加载,链接,初始化)1

    Java虚拟机(JVM)是Java程序的核心组件,它负责执行字节码并管理内存。在JVM中,类的加载、链接和初始化是至关重要的三个步骤,它们共同确保了程序的正常运行。 1. **加载(Loading)** 加载阶段是JVM寻找和导入...

    深入研究Java类加载机制 深入研究Java类加载机制

    Java类加载机制是Java程序运行的第一步,它对于理解Java虚拟机(JVM)的行为至关重要。类加载过程涉及到类的加载、链接(验证、准备、解析)、初始化等阶段,并且这一过程是由类加载器系统完成的。 #### 二、类加载...

    JAVA类加载

    【Java 类加载】是Java虚拟机(JVM)在运行时动态加载类文件到内存中的过程,这是Java语言动态性的重要体现。Java程序中的每个类和接口都被编译成独立的`.class`文件,这些文件作为Java运行环境的动态加载单元。 在...

    java虚拟机工作原理详解

    Java虚拟机(JVM)是Java程序的核心执行环境,负责运行编译后的Java字节码。本文将深入探讨JVM的工作原理,主要包括类加载器、类加载过程以及运行数据区。 ### 类加载器 类加载器是JVM的重要组成部分,它们负责从...

    Dynamic Class Loading in the Java Virtual Machine

    动态类加载是Java虚拟机(JVM)的一项核心特性,它为Java平台带来了强大的功能:即能够在运行时安装软件组件。这一机制不仅提高了系统的灵活性,还优化了资源管理,确保类型安全的同时支持用户自定义扩展。 #### ...

    Java类加载内幕详细讲解

    通过掌握类加载的过程、类加载器的工作原理以及类加载的线程安全性等方面的知识,开发者能够更好地利用Java的动态特性,优化程序性能,并避免常见的异常问题,如`ClassNotFoundException`等。此外,对于自定义类加载...

    JVM(三):类加载机制(类加载过程和类加载器)1

    Java虚拟机(JVM)的类加载机制是Java应用程序运行灵活性的关键。类加载涉及多个步骤,包括加载、验证、准备、解析、初始化、使用和卸载。这些阶段确保了类的正确加载、验证其安全性和有效运行。 1. **加载...

Global site tag (gtag.js) - Google Analytics