java 卸载class_Java Class卸载与ClassLoader

java 卸载class_Java Class卸载与ClassLoaderJVM中的Class只有满足以下三个条件,才能被GC回收,也就是该Class被卸载(unload):-该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。-加载该类的ClassLoader已经被GC。-该类的Java.lang.Class对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法jsp和java类是完全不一样的概念。jsp->servlet…

大家好,又见面了,我是你们的朋友全栈君。

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

类加载器的种类:

Bootstrap ClassLoader/启动类加载器

主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作。

Extension ClassLoader/扩展类加载器

主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作。

System ClassLoader/系统类加载器

主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作。

User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)

在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性。

类加载器的特性:

每个ClassLoader都维护了一份自己的名称空间, 同一个名称空间里不能出现两个同名的类。

为了实现java安全沙箱模型顶层的类加载器安全机制, java默认采用了 ” 双亲委派的加载链 ” 结构。

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

classloader-load-class.jpg

classloader-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;

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/144573.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 蓝墨云班课资源下载不了_蓝墨云班课老师怎么用

    蓝墨云班课资源下载不了_蓝墨云班课老师怎么用看见有人详细讲解了下载文件的原理,在这里我就不赘述了,直接上写好的代码。可能乱了点。有一点要提前说一下,做这个的时候,我想着只下载没有获得经验的文件。已经获得过经验的文件因为我用不到,所以就不用下,当然,改一下代码的话没货的经验的也能下。相关的代码在download_sours函数里面,jy表示的是经验,jy=N代表没获得经验的文件,改一下就行,去掉这个判断条件就能下载已经获得经验的资源了。最后,封装好的软件下载链接在文章最末尾importosimportreimporttimeimpor

    2022年10月30日
  • Java之Java开发工具

    Java之Java开发工具

  • Oracle数据库分区表原理学习

    Oracle数据库分区表原理学习当表中的数据量不断增大,查询数据的速度就会变慢,应用程序的性能就会下降,这时就应该考虑对表进行分区。Oracle提供了分区技术以支持VLDB(VeryLargeDataBase)。分区表通过对分区列的判断,把分区列不同的记录,放到不同的分区中。分区完全对应用透明。Oracle的表分区功能通过改善可管理性、性能和可用性,从而为各式应用程序带来了极大的好处。通常,分区可以使某些查询以及维护

  • tar压缩文件

    tar压缩文件tar压缩的优点:兼容性好使用tar压缩文件tar-zcvftest.tar.gz./test/该命令表示压缩当前文件夹下的文件夹test,压缩后缀名为test.tar.gz如果不需要压缩成gz,只需要后缀为tar格式的,那么输入如下命令:tar-cvftest.tar./test/使用tar解压文件tar-xzvftest.tar.gz该命令表示把后缀为.tar.gz的文件解压到当前文件夹下。如果压缩文件的后缀是.tar,没有gz,则使用命令:tar-xvf

  • databus mysql搭建_databus bootstrap 部署

    databus mysql搭建_databus bootstrap 部署databus分为relaybootstrap-producer(bst-producer)bootstrap-server(bst-server)client,他们之间的关系可以去网上找这里主要介绍部署这四个工程的方法1relay侦听端口为111151.1relay.propertiesdatabus.relay.container.httpPort=11115data…

    2022年10月17日
  • 关于iPhone尺寸与分辨率[通俗易懂]

    浅谈不同型号iPhone的尺寸与不同的分辨率首先谈谈编者对分辨率这个概念的认知,分辨率与清晰度挂钩,同样尺寸的视图,分辨率越高清晰度越好。另外还要引出一个重要的概念:PPI(pixelsperinch)PPI是图像分辨率的单位,图像PPI值越高,画面的细节就越丰富,因为单位面积的像素数量越多,一般PPI>300人眼难以分辨出来。分辨率分为水平和垂直两种,

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号