java类hotswap_java类加载器系统构造(含hotswap原理).

jvm classLoader architecture :

a, Bootstrap ClassLoader/启用类加载器

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

b, Extension ClassLoader/伸展类加载器

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

c, System ClassLoader/系统类加载器

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

b, User Custom

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

在过程运行其间, 穿越java.lang.ClassLoader的子类动态加载class文件,

揭示java动态实时类装入个性.

类加载器的个性:

1, 每个ClassLoader都维护了一份自己的名目空间, 统一个名目空间里不能揭示两个同名的类。

2, 为了告终java平安沙箱模型顶层的类加载器平安机制, java默认批准了 ”

双亲派遣的加载链 ” 构造.

如下图:

Class Diagram:

类图中, BootstrapClassLoader是一个独自的java类, 其恳挚这里,

不该当叫他是一个java类。

因为, 它曾经全?**扌雑ava告终了。

它是在jvm启用时, 就被构造起来的, 负责java平台中心库。(翔实上面曾经有推荐)

启用类加载告终 (其实我们无须关怀这块, 然而有乐趣的, 能够琢磨一下 ):

bootstrap classLoader 类加载原理摸索

自定义类加载器加载一个类的环节 :

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)

;

}

}

用Class.forName加载类

Class.forName利用的是被调用者的类加载器来加载类的.

这种个性, 验证了java类加载器中的名目空间是单一的, 不会互相扰乱.

即在等闲理况下, 保证统一个类中所关系的其他类都是由目前类的类加载器所加载的.

public

static

Class

forName(

String

className)

throws

ClassNotFoundException

{

return

forName0(

className, true

, ClassLoader

.getCallerClassLoader

(

)

)

;

}

private

static

native

Class

forName0(

String

name, boolean

initialize,

ClassLoader

loader)

throws

ClassNotFoundException

;

上图中 ClassLoader.getCallerClassLoader

即便获得调用目前forName措施的类的类加载器

线程上下文类加载器

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).

自定义的类加载器告终

defineClass(String name, byte[] b, int off, int

len,ProtectionDomain protectionDomain)

是java.lang.Classloader提供给开发人员, 用来自定义加载class的接口.

利用该接口, 能够动态的加载class文件.

例如,

在jdk中, URLClassLoader是配合findClass措施来利用defineClass,

能够从网络或硬盘上加载class.

而利用类加载接口, 并加上自己的告终逻辑, 还能够定制出更多的高级个性.

例如,

一个容易的hot swap 类加载器告终:

import

java.io.File

;

import

java.io.FileInputStream

;

import

java.lang.reflect.Method

;

import

java.net.URL

;

import

java.net.URLClassLoader

;

public

class

HotSwapClassLoader extends

URLClassLoader

{

public

HotSwapClassLoader(

URL

[

]

urls)

{

super

(

urls)

;

}

public

HotSwapClassLoader(

URL

[

]

urls, ClassLoader

parent)

{

super

(

urls, parent)

;

}

public

Class

load(

String

name)

throws

ClassNotFoundException

{

return

load(

name, false

)

;

}

public

Class

load(

String

name, boolean

resolve)

throws

ClassNotFoundException

{

if

(

null

!=

super

.findLoadedClass

(

name)

)

return

reload(

name, resolve)

;

Class

clazz =

super

.findClass

(

name)

;

if

(

resolve)

super

.resolveClass

(

clazz)

;

return

clazz;

}

public

Class

reload(

String

name, boolean

resolve)

throws

ClassNotFoundException

{

return

new

HotSwapClassLoader(

super

.getURLs

(

)

, super

.getParent

(

)

)

.load

(

name, resolve)

;

}

}

public

class

A {

private

B b;

public

void

setB(

B b)

{

this

.b

=

b;

}

public

B getB(

)

{

return

b;

}

}

public

class

B {

}

这个类的作用是能够重新载入同名的类, 然而, 为了告终hotswap, 老的对象事态

必需穿越其他措施拷贝到重载过的类生成的崭新实例中来。(A类中的b实例)

而新实例所依靠的B类万一与老对象不是统一个类加载器加载的,

将会抛出种类转换失常(ClassCastException).

为打听决这种问题, HotSwapClassLoader自定义了load措施. 即目前类是由切身classLoader加载的,

而内部依靠的类还是老对象的classLoader加载的.

public

class

TestHotSwap {

public

static

void

main(

String

args[

]

)

{

A a =

new

A(

)

;

B b =

new

B(

)

;

a.setB

(

b)

;

System

.out

.printf

(

"A classLoader is %s n"

, a.getClass

(

)

.getClassLoader

(

)

)

;

System

.out

.printf

(

"B classLoader is %s n"

, b.getClass

(

)

.getClassLoader

(

)

)

;

System

.out

.printf

(

"A.b classLoader is %s n"

, a.getB

(

)

.getClass

(

)

.getClassLoader

(

)

)

;

HotSwapClassLoader c1 =

new

HotSwapClassLoader(

new

URL

[

]

{

new

URL

(

"file:/e

:/t

est/"

)} , a.getClass().getClassLoader());

Class clazz = c1.load("

test.hotswap

.A

");

Object aInstance = clazz.newInstance();

Method method1 = clazz.getMethod("

setB ", B.class);

method1.invoke(aInstance, b);

Method method2 = clazz.getMethod("

getB ", null);

Object bInstance = method2.invoke(aInstance, null);

System.out.printf("

reloaded A.b

classLoader is %

s n", bInstance.getClass().getClassLoader());

}

}

输出

A classLoader is sun.misc.Launcher$AppClassLoader@19821f

B classLoader is sun.misc.Launcher$AppClassLoader@19821f

A.b classLoader is sun.misc.Launcher$AppClassLoader@19821f

reloaded A.b classLoader is

sun.misc.Launcher$AppClassLoader@19821fExample ex = new Example();

Dimension d = ex.getValues(); d.height = -5; d.width =

-10;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值