`
wbj0110
  • 浏览: 1610013 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

Java Class卸载与ClassLoader ,class热替换

    博客分类:
  • Java
阅读更多

JVM中的Class只有满足以下三个条件,才能被GC回收,也就是该Class被卸载(unload):

   - 该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。
   - 加载该类的ClassLoader已经被GC。
   - 该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法

 

jsp和java类是完全不一样的概念。

jsp->servlet 在web容器中,你的servlet是单例的,也是无状态的,线程安全的。也就是只有一个对象,

jsp改变以后,web容器只要把相应的servlet对象更新就好了。

而java呢?

可能这个类在你的应用中有n个实例,与这些实例单向,双向关联的又有n个实例。如果你修改了,这些jvm存在的老的实例对象怎么办????

java这类静态语言无法实现象asp,php,jsp的效果的。


 weblogic热部署原理

Weblogic允许在wls运行时部署组件的新版本。这个过程被称作热部署。因为java classloader没有任何一种机制来卸下一系列存在的类,也不能用类的新版本来替换老版本,为了在一个运行的虚拟机中更新相关的类,classloader必须被替换掉。当它被替换时,它所装载的所有类以及衍生的子classloader也要被重新装载。这些类的所有实例也必需被重新装载。在wls中,每一个应用组件都有一个层次化的classloaders,它们都是system classloader的子类,这种结构有助于每个应用或应用的一部分能被单独重新加载,而不会影响其它的组件。

 

类加载器的种类:

  1. Bootstrap ClassLoader/启动类加载器 
    主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作。
  2. Extension ClassLoader/扩展类加载器 
    主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作。
  3. System ClassLoader/系统类加载器 
    主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作。
  4. User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类) 
    在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性。

类加载器的特性:

 

  1. 每个ClassLoader都维护了一份自己的名称空间, 同一个名称空间里不能出现两个同名的类。
  2. 为了实现java安全沙箱模型顶层的类加载器安全机制, java默认采用了 " 双亲委派的加载链 " 结构。

 

 

自定义类加载器加载一个类的步骤

classloader-load-classclassloader-load-class

 

ClassLoader 类加载逻辑分析, 以下逻辑是除 BootstrapClassLoader 外的类加载器加载流程:

// 检查类是否已被装载过        

Class c = findLoadedClass(name);        

if (c == null ) {        

         // 指定类未被装载过        

         try {        

                 if (parent != null ) {        

                         // 如果父类加载器不为空, 则委派给父类加载        

                         c = parent.loadClass(name, false );        

                 } else {        

                         // 如果父类加载器为空, 则委派给启动类加载加载        

                         c = findBootstrapClass0(name);        

                 }        

         } catch (ClassNotFoundException e) {        

                 // 启动类加载器或父类加载器抛出异常后, 当前类加载器将其        

                 // 捕获, 并通过findClass方法, 由自身加载        

                 c = findClass(name);        

         }        

}

 

 

线程上下文类加载器

java默认的线程上下文类加载器是 系统类加载器(AppClassLoader)。

// Now create the class loader to use to launch the application        

try {        

        loader = AppClassLoader.getAppClassLoader(extcl);        

} catch (IOException e) {        

        throw new InternalError(        

"Could not create application class loader" );        

}         

     

// Also set the context class loader for the primordial thread.        

Thread.currentThread().setContextClassLoader(loader);    

 

以上代码摘自sun.misc.Launch的无参构造函数Launch()。

使用线程上下文类加载器, 可以在执行线程中, 抛弃双亲委派加载链模式, 使用线程上下文里的类加载器加载类.

典型的例子有, 通过线程上下文来加载第三方库jndi实现, 而不依赖于双亲委派.

大部分java app服务器(jboss, tomcat..)也是采用contextClassLoader来处理web服务。

还有一些采用 hotswap 特性的框架, 也使用了线程上下文类加载器, 比如 seasar (full stack framework in japenese).

线程上下文从根本解决了一般应用不能违背双亲委派模式的问题.

使java类加载体系显得更灵活.

随着多核时代的来临, 相信多线程开发将会越来越多地进入程序员的实际编码过程中. 因此,

在编写基础设施时, 通过使用线程上下文来加载类, 应该是一个很好的选择。

当然, 好东西都有利弊. 使用线程上下文加载类, 也要注意, 保证多根需要通信的线程间的类加载器应该是同一个,

防止因为不同的类加载器, 导致类型转换异常(ClassCastException)。

 

三.命名空间及其作用
每个类装载器有自己的命名空间,命名空间由所有以此装载器为创始类装载器的类组成。不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的reference,还是可以访问另一命名空间的类。
 
例2演示了一个命名空间的类如何使用另一命名空间的类。在例子中,LoaderSample2由系统类装载器装载,LoaderSample3由自定义的装载器loader负责装载,两个类不在同一命名空间,但LoaderSample2得到了LoaderSample3所对应的Class对象的reference,所以它可以访问LoaderSampl3中公共的成员(如age)。
例2不同命名空间的类的访问
/*LoaderSample2.java*/

import    java.net. * ; 

import    java.lang.reflect. * ; 

public     class    LoaderSample2 { 

         public     static     void    main(String[] args) { 

                 try    { 

                        String path    =    System.getProperty( " user.dir " ); 

                        URL[] us    =    { new    URL( " file:// "     +    path    +     " /sub/ " )}; 

                        ClassLoader loader    =     new    URLClassLoader(us); 

                        Class c    =    loader.loadClass( " LoaderSample3 " ); 

                        Object o    =    c.newInstance(); 

                        Field f    =    c.getField( " age " ); 

                         int    age    =    f.getInt(o); 

                        System.out.println( " age is    "     +    age); 

                }    catch    (Exception e) { 

                        e.printStackTrace(); 

                } 

        } 

}

/*sub/Loadersample3.java*/

public     class    LoaderSample3 { 

         static    { 

                System.out.println( " LoaderSample3 loaded " ); 

        } 

         public     int    age    =     30 ; 

}

编译:javac LoaderSample2.java; javac sub/LoaderSample3.java

运行:java LoaderSample2

LoaderSample3 loaded

age is 30

从运行结果中可以看出,在类LoaderSample2中可以创建处于另一命名空间的类LoaderSample3中的对象并可以访问其公共成员age。

 

说明:如果LoaderSample3在classpath下能够找到,则由URLClassLoader的parent loader AppClassLoader来加载,如果不在classpath下

则由URLClassLoader自己加载,即LoaderSample3.getClass().getClassLoader() 是URLClassLoader

运行时包(runtime package)

由同一类装载器定义装载的属于相同包的类组成了运行时包,决定两个类是不是属于同一个运行时包,不仅要看它们的包名是否相同,还要看的定义类装载器是否相同。只有属于同一运行时包的类才能互相访问包可见的类和成员。这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自己定义了一个类java.lang.Yes,并用用户自定义的类装载器装载,由于java.lang.Yes和核心类库java.lang.*由不同的装载器装载,它们属于不同的运行时包,所以java.lang.Yes不能访问核心类库java.lang中类的包可见的成员。 

 

总结
命名空间并没有完全禁止属于不同空间的类的互相访问,双亲委托模型加强了Java的安全,运行时包增加了对包可见成员的保护。
 
二.    扩展ClassLoader方法

我们目的是从本地文件系统使用我们实现的类装载器装载一个类。为了创建自己的类装载器我们应该扩展ClassLoader类,这是一个抽象类。我们创建一个FileClassLoader extends ClassLoader。我们需要覆盖ClassLoader中的findClass(String name)方法,这个方法通过类的名字而得到一个Class对象。

         public    Class findClass(String name) 

        { 

                 byte [] data    =    loadClassData(name); 

                 return    defineClass(name, data,    0 , data.length); 

        }

我们还应该提供一个方法loadClassData(String name),通过类的名称返回class文件的字 
节数组。然后使用ClassLoader提供的defineClass()方法我们就可以返回Class对象了。

public     byte [] loadClassData(String name) 

        { 

                FileInputStream fis    =     null ; 

                 byte [] data    =     null ; 

                 try    

                { 

                        fis    =     new    FileInputStream( new    File(drive    +    name    +    fileType)); 

                        ByteArrayOutputStream baos    =     new    ByteArrayOutputStream(); 

                         int    ch    =     0 ; 

                         while    ((ch    =    fis.read())    !=     - 1 ) 

                        { 

                                baos.write(ch); 

                                

                        } 

                        data    =    baos.toByteArray(); 

                }    catch    (IOException e) 

                { 

                        e.printStackTrace(); 

                } 

                 

                 return    data; 

        }

 

自定义ClassLoader实现java 热替换:http://www.ibm.com/developerworks/cn/java/j-lo-hotswapcls/

 

 

Add dynamic Java code to your application 利用动态代理实时监控类的变化并重新加载

http://www.javaworld.com/article/2071777/design-patterns/add-dynamic-java-code-to-your-application.html

 

 

 

Java 类的热替换 —— 概念、设计与实现

https://www.ibm.com/developerworks/cn/java/j-lo-hotswapcls/

 

 

 

http://www.blogjava.net/heavensay/archive/2015/11/06/389685.html

 

深入探索 Java 热部署

http://www.hollischuang.com/archives/592

 

http://fengzhiyu-sh.iteye.com/blog/1608115

 

 jar包 热加载/卸载 的初步实现

http://www.cnblogs.com/xiaodl/p/plugin_hot_load.html

 

 

 

 

 

分享到:
评论

相关推荐

    深入Java虚拟机_ClassLoader

    在Java中,每个类都由一个对应的Class对象表示,而这些Class对象的创建过程就离不开ClassLoader。 1. 类加载机制: Java的类加载机制遵循“双亲委派模型”。当一个类被加载时,它首先会委托给父类加载器尝试加载,...

    Java SE: ClassLoader in depth

    对于标题“Java SE: ClassLoader in depth”和描述中提到的“源码”、“工具”,实际上在给出的内容部分并没有任何与Java ClassLoader深入相关的技术信息。所提供的内容实际上是一份公司入职报到的指南,与Java编程...

    了解Java ClassLoader

    - 开发者可以继承java.lang.ClassLoader并重写findClass()或loadClass()方法,实现自定义的类加载逻辑,例如从网络、数据库或其他非标准位置加载类。 - 自定义ClassLoader在插件系统、热部署、模块化系统等领域有...

    java classloader讲义-淘宝网

    1. **热更新实现**:通过自定义ClassLoader,可以在不重启服务器的情况下,加载新的类文件替换旧的类文件。 2. **多租户隔离**:淘宝网存在大量的商户和服务,每个服务都可能有自己的类加载器,这样可以有效地隔离...

    支持Java热部署的插件

    Java热部署主要涉及到JVM(Java虚拟机)和类加载器(ClassLoader)的工作机制。JVM在运行时会加载类文件到内存中,当类被修改后,热部署插件能够检测到这种变化,并替换内存中的旧版本类,而不需要停止服务。这个...

    class文件热加载,上传class文件实现热加载

    "class文件热加载,上传class文件实现热加载"这个主题主要涉及到Java应用的运行时动态更新机制。下面将详细介绍这个过程及其相关知识点。 1. **Java类加载器**: - Java虚拟机(JVM)通过类加载器来加载类。默认有...

    关于java热部署知识.doc

    然而,Java虚拟机(JVM)规范并未直接提供对热部署的支持,主要是由于类加载和卸载的机制。 Java的类加载机制基于双亲委派模型,它确保了类加载的安全性和一致性。Bootstrap ClassLoader首先加载JRE的核心库,接着...

    classloader 热部署

    本文将深入探讨Classloader与热部署之间的关系,以及如何实现这一功能。 首先,我们来看一下默认的类加载机制。Java的类加载过程遵循“双亲委派模型”(Delegation Model),即新类的加载请求会先传递给父类加载器...

    项目运行期间热插拔接口实现类

    3. 自定义类加载器:继承`java.lang.ClassLoader`,重写`findClass()`方法,使其能够加载指定路径下的实现类。 4. 动态加载:在运行时根据需求,通过自定义类加载器加载相应的实现类。 5. 实例化和使用:加载类后,...

    Java基于自定义类加载器实现热部署过程解析

    为了实现热部署,需要使用自定义的ClassLoader替换系统的加载器,创建一个新的ClassLoader,再用它加载Class,得到的Class对象就是新的(因为不是同一个类加载器),再用该Class对象创建一个实例,从而实现动态更新...

    2015-11-ClassLoaders-Selajev.pdf

    自定义类加载器可以继承抽象类java.lang.ClassLoader,并重写findClass()方法来实现自定义的类查找和加载机制。使用自定义类加载器可以用于实现类隔离、热替换代码等高级功能。 类加载器的设计允许Java应用使用多...

    Java深度历险CH02

    这是通过继承`java.lang.ClassLoader`类并重写`findClass`方法来实现的。自定义类别加载器可以用来实现更高级的动态性需求,例如热部署(Hot Deployment)。 #### 热部署(Hot Deployment) 热部署是指在应用程序...

    自定义Java类加载器

    - **热部署**:在开发环境中,可以实现快速替换和更新类,而无需重启应用程序。 - **模块化系统**:不同模块使用不同的类加载器,隔离不同模块间的类,避免冲突。 - **安全沙箱**:每个加载器都有自己的命名空间,...

    类加载器文件

    **类加载器(ClassLoader)**是Java虚拟机(JVM)中的一个重要组成部分,它负责将编译好的`.class`文件加载到JVM中,使得这些类可以在Java环境中运行。类加载器不仅能够加载类,还能够根据不同的需求定制加载方式,如从...

    Java虚拟机工作原理详解

    * User-Defined Class Loader:这是开发人员通过拓展 ClassLoader 类定义的自定义加载器,加载程序员定义的一些类。 类加载器之间存在一种委派模式(Delegation Mode),当 JVM 加载一个类的时候,下层的加载器会将...

    java类加载机制原理与实现

    Java 类加载机制原理与实现 Java 类加载机制是 Java 虚拟机(JVM)的一部分,负责将编译后的 Java 字节码文件加载到 JVM 中,以便执行 Java 程序。类加载机制是 JVM 的核心组件之一,对 Java 程序的执行和安全性起...

    2 类加载子系统.md,学习代码

    在开发环境中,为了提高效率,开发者常常需要实现类的热替换,这就涉及到了类的重新加载技术,如JRebel等工具就提供了这样的功能。 9. **类加载与垃圾回收** 类实例的生命周期与类加载器密切相关,当一个类加载器...

    从JDK源码级别剖析JVM类加载机制

    6. **类加载器与热部署**: 在JDK源码中,类加载机制也为动态替换和更新类提供了可能,这在应用服务器的热部署场景中尤为重要。通过替换类加载器或者重新加载类,可以在不重启应用的情况下更新代码。 7. **双亲...

    Java类加载机制 PDF 下载

    9. **类加载器优化**:合理设计和使用自定义类加载器,可以实现类的热替换,提升应用更新效率。此外,对于大型项目,可以利用类加载器隔离技术,减少类间的相互影响,提高系统稳定性。 10. **类的可见性**:类之间...

Global site tag (gtag.js) - Google Analytics