- 浏览: 579954 次
- 性别:
- 来自: 0
文章分类
最新评论
-
springOfJava:
中岛嘉兰 写道jdk8表示都是waiting...wait01 ...
最简实例说明wait、notify、notifyAll的使用方法 -
中岛嘉兰:
中岛嘉兰 写道jdk8表示都是waiting...wait01 ...
最简实例说明wait、notify、notifyAll的使用方法 -
中岛嘉兰:
jdk8表示都是waiting...wait01 begin ...
最简实例说明wait、notify、notifyAll的使用方法 -
zhoujianboy:
推荐一篇文章 JVM内存模型和JVM参数的关系:http:// ...
图解JVM内存模型 -
timothy2005:
楼主最下方的链接是不是放错了?原本说该篇文章列出了其中一种自定 ...
图解classloader加载class的流程及自定义ClassLoader
http://blog.csdn.net/totodo/archive/2005/01/28/271798.aspx
也许你认为Class Load是一个高级话题,不管怎样,作为开发者你还是要了解它。
理解CLassLoader
也许你欣然以为这样写没问题,但实际上你错了。
java.lang.Class klass = Myclass.class;
而实例化一个类,可以是:Myclass myclass = new Myclass() 也可以是: myclass.newInstance();
JDK中除了ClassLoader可以加载类之外,还有以下这些也可以。
-
java.net.URLClassLoader
-
java.security.SecureClassLoader
-
java.rmi.server.RMIClassLoader
-
sun.applet.AppletClassLoader
(String name, boolean resolve)
throws ClassNotFoundException{
// First check if the class is already loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke
// findClass to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
public MyClassLoader(){
super(MyClassLoader.class.getClassLoader());
}
}
public MyClassLoader(){
super(getClass().getClassLoader());
}
}
protected Class<?> findClass(String name)
throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
每个ClassLoader出来的类都是不同的, 如果有两个ClassLoader载入两各相同的程序,defineClass()定义得两个类也是不同得。详细请看( Java language specification )
根据上面得解析,既然由两个classLoader()载入Target.class得字节码 ,那defineClass()就会产生两个class的定义。
Target target1 = (Target) target2; 是不正确的 。target1 和 target2是由两个不同的classloader定义的。
上面说一个class标识是由于package+classname组成得。 对于所有实现java.io.Serializable 接口的类,都是由serialVersionUID管理这些类得版本( RMI,JNDI,Security里都有这样一个ID) 。它用64位的Hash来表示 (这个Hash由classname,filed,method组成)。从技术上讲如果classname,field,mehtod所构成的Hash都一样,那就会认为是同一个版本。
log("this = " + this + "; Version.fx(1).");
}
log("this = " + this + "; Version.fx(2).");
}
%JAVA_HOME%\bin\java Test 结果如下图
图 3.
classPath得目录设为v1
%JAVA_HOME%\bin\java Test
结果如下图:
图 4.
classpath目录设为v2
很明显,上面的例子中能从classpath中找到先后次序。如果我们把v1,v2的version.Version。都删调。而把他们打成一个myextension.jar包,放到java.ext.dirs目录下。。这时候就通过ExtClassLoader 来装载了,而不是AppClassLoader.
结果会是如下:
图 5. AppClassLoader
and ExtClassLoader
注意看 sun.misc.Launcher$ExtClassLoader@a9c85c 这说明是ExtClassLoader 加载了。
继续往下看,另外一个例子。 在differentversions 目录下的例子,里面包含了RMI的ServerImpl这样一个执行引擎。Client实现了common.TaskIntf接口。 两个 client.TaskImpl分别如下:
static{
log("client.TaskImpl.class.getClassLoader
(v1) : " + TaskImpl.class.getClassLoader());
}
public void execute(){
log("this = " + this + "; execute(1)");
}
另一个则是:
static{
log("client.TaskImpl.class.getClassLoader
(v1) : " + TaskImpl.class.getClassLoader());
}
public void execute(){
log("this = " + this + "; execute(2)");
}
这样子来执行(顺序随便,这里把 %CURRENT_ROOT%\client2放在前面 ):
CLASSPATH=%CURRENT_ROOT%\common;%CURRENT_ROOT%\server;
%CURRENT_ROOT%\client2;%CURRENT_ROOT%\client1
%JAVA_HOME%\bin\java server.Server
先启动Server..
分别把两个client提交给服务器执行, (即便执行程序中得client1.bat 和 client2.bat server监控屏幕如图6所示。)
图 6. Execution Engine Server console
再来看下面两个图(图7和图8),分别是client端得执行显示。
图 7. Execution Engine Client 1 console
图 8. Execution Engine Client 2 console
纵观上面三次执行结果,发现由于服务器启动得时候使用了AppClassLoader.所以无论怎么样都是载入得是client2(因为client2的classpath次序比较在前),
这里client1 很郁闷,它在自己那执行明明是 execute(1) 通过 RMI 发送给服务器端执行就成了 execute(2)..
值得注意的是: 在client1,client2分别发送给服务器执行之后,服务器端显示的记录是:
client.TaskImpl.class.getClassLoader(v2):sun.misc.lancuher@AppClassLoader@xxxx zhiz只执行了一次。而
this=client.TaskImpl@xxxxx
execute(2);执行了两次
上面已经讲到过了,对于一个ClassLoader来讲 同样的page+className 只能定义一个 class,而不同的ClassLoader即便加载同一个page.className 也会定义不同的class
到这里,我才发现,解决上面提出得那个问题似乎并不容易。:(。
那如何解决呢?答案就是---使用自定义得classLoader ..
如果各位等不急的话, 先请看(目录中 differentversionspush 里面的代码)
很显然,我们很有必要写自定义的classloader.
如何构造使用自定义的ClassLoader
既然自定义的ClassLoader,能解决上述问题,那接下去看看,我们如何来使用自定义的ClassLoader。
结合本文种的原码---(在differentversionspush的目录里),有个FileSystemClassLoader,类图描述如下:
图9.
看看他的方法 findClassBytes(String className);
public byte[] findClassBytes(String className){
try{
String pathName = currentRoot +
File.separatorChar + className.
replace('.', File.separatorChar)
+ ".class";
FileInputStream inFile = new
FileInputStream(pathName);
byte[] classBytes = new
byte[inFile.available()];
inFile.read(classBytes);
return classBytes;
}
catch (java.io.IOException ioEx){
return null;
}
}
public Class findClass(String name)throws
ClassNotFoundException{
byte[] classBytes = findClassBytes(name);
if (classBytes==null){
throw new ClassNotFoundException();
}
else{
return defineClass(name, classBytes,
0, classBytes.length);
}
}
public Class findClass(String name, byte[]
classBytes)throws ClassNotFoundException{
if (classBytes==null){
throw new ClassNotFoundException(
"(classBytes==null)");
}
else{
return defineClass(name, classBytes,
0, classBytes.length);
}
}
public void execute(String codeName,
byte[] code){
Class klass = null;
try{
klass = findClass(codeName, code);
TaskIntf task = (TaskIntf)
klass.newInstance();
task.execute();
}
catch(Exception exception){
exception.printStackTrace();
}
}
这 个类FileSystemClassLoader 被client使用了,用来定义class, 并且把它把client.TaskImpl(v1)转化为 byte[], 然后 byte[]发送到RMI Server执行。(上面讲了defineClass()能够执行任何字节码,来自编译后的文件,网络甚至是BCEL 字节码引擎库), 在Server端 ,又可以通过FileSystemClassLoader 以为byte[]的形式定义出 client.TaskImpl。
请看Client端的代码:
public class Client{
public static void main (String[] args){
try{
byte[] code = getClassDefinition
("client.TaskImpl");
serverIntf.execute("client.TaskImpl",
code);
}
catch(RemoteException remoteException){
remoteException.printStackTrace();
}
}
private static byte[] getClassDefinition
(String codeName){
String userDir = System.getProperties().
getProperty("BytePath");
FileSystemClassLoader fscl1 = null;
try{
fscl1 = new FileSystemClassLoader
(userDir);
}
catch(FileNotFoundException
fileNotFoundException){
fileNotFoundException.printStackTrace();
}
return fscl1.findClassBytes(codeName);
}
}
在RMI服务器端ServerImpl 程序里, 接受到来自client的字节码(byte[]),于是FileSystemClassLoader 会从byte[]构造出一个class, 实例话,并且执行。
有一点要注意:每次接收到一个client的请求,FileSystemClassLoader都会重新实例化(执行结果中可以看出来),这就意
味着,client.Impl不在是在classpath中被找到的,而是通过FileSystemClassLoader 的findClass()
来执行deFineClass(),这样每次 FileSystemClassLoader 都是创建新的实例,,自然
deFine出来的class也是不同的。 这样,我们就能在RMI的执行中区分出 这两个class来。(client.TaskImpl !=
client.TaskImp 在上篇就已经得出结论了。 )
看看服务器端的执行代码:
public void execute(String codeName, byte[] code)throws RemoteException{
FileSystemClassLoader fileSystemClassLoader = null;
try{
fileSystemClassLoader = new FileSystemClassLoader();
fileSystemClassLoader.execute(codeName, code);
}
catch(Exception exception){
throw new RemoteException(exception.getMessage());
}
}
服务器端的执行结果:
图10,服务器端显示
下面两图分别是客户端显示的。
图11. client1的执行显示
图12. client2执行结果
哈,上面洋洋洒洒那么多,总算是一步一步的教会了大家 如何在同一个VM虚拟机中,执行“不同版本”的代码 。(这些代码有同样的类名和包名)。
Class Loaders 在 J2EE 中应用。
我的一个A_war.war的web项目中 代码是 com.mycom.Test 而我在另外一个B_war.war的wenb项目中的 代码也是com.mycom.Test 而他们照样工作的好好的。
当一个大型的 EJB项目,一台服务器上部署了多个 EJB,War工程时候,他们也不会互相影响。AppServer还会有自己的装载策略,比如你web中用的jar包,会优先于AppServer本身所带有的。
另外,J2EE的ClassLoader机制更详细的能容你可以参考Tss上的这篇文章。 Understanding J2EE Application Server Class Loading Architectures "
资源文件:
原文:
http://www.onjava.com/pub/a/onjava/2005/01/26/classloading.htm
发表评论
-
jvm crash,疑似GC的bug
2010-11-18 11:16 4123在对一个应用做压力的时候,不定时发生jvm crash,查看h ... -
三种GC大揭秘
2009-09-23 09:12 10005/** * 转载请注明作者longdick ht ... -
图解JVM内存模型
2009-09-22 00:25 23591/** * 转载请注明作 ... -
JAVA HOTSPOT VM参数大全
2009-09-20 20:06 3207/** * 转载请注明作者longdick ht ... -
图解JVM在内存中申请对象及垃圾回收流程
2009-09-14 14:15 11120/** * 转载请注明作 ... -
Java序列化算法透析
2009-08-27 20:31 8569/** * 转载请注明作 ... -
图解classloader加载class的流程及自定义ClassLoader
2009-08-07 11:59 64833/** * 转载请注明作者longdick ht ... -
ClassLoader分析
2007-11-08 15:38 1598ClassLoader 是 Java 虚拟机 ...
相关推荐
powermock-classloading-xstream-1.4.7powermock-classloading-xstream-1.4.7powermock-classloading-xstream-1.4.7powermock-classloading-xstream-1.4.7powermock-classloading-xstream-1.4.7powermock-class...
org.springframework.instrument.classloading-3.0.0.M4.jar
最底一分,xstream-1.4.8的jar包、源码、说明文档.zip
ClassFinal是一款java class文件安全加密工具,支持直接加密jar包或war包,无需修改任何项目代码,兼容spring-framework;可避免源码泄漏或字节码被反编译。执行java -jar classfinal-fatjar.jar 后按提示即可完成...
赠送jar包:classgraph-4.8.83.jar; 赠送原API文档:classgraph-4.8.83-javadoc.jar; 赠送源代码:classgraph-4.8.83-sources.jar; 赠送Maven依赖信息文件:classgraph-4.8.83.pom; 包含翻译后的API文档:class...
ClassFinal-java class文件安全加密工具
class-dump, class-dump-z.exe,class-dump-z win版本
JAVA反射机制-Class类-Class对象的获取.pdf
django-classy-tags, 基于类的Django 模板标记 django-classy-tags请参考文档/目录中的文档以获得帮助。 有关HTML呈现版本的信息,请参见这里的 。 这里项目这个项目的目标是创建一种新的编写 Django 模板标签的方法...
In this article I want to discuss the lazy loading mechanism provided by NHibernate. It is recommended for maximum flexibility to define all relations in your domain as lazy loadable. This is the ...
线性串联的FAE计算。假定末级包络增益确定的情况下,驱动效率影响PA线性度。10W氮化镓功率管的F类驱动级设计。
赠送jar包:classgraph-4.8.90.jar; 赠送原API文档:classgraph-4.8.90-javadoc.jar; 赠送源代码:classgraph-4.8.90-sources.jar; 赠送Maven依赖信息文件:classgraph-4.8.90.pom; 包含翻译后的API文档:class...
赠送jar包:classgraph-4.8.83.jar; 赠送原API文档:classgraph-4.8.83-javadoc.jar; 赠送源代码:classgraph-4.8.83-sources.jar; 赠送Maven依赖信息文件:classgraph-4.8.83.pom; 包含翻译后的API文档:class...
Spring3.1 定时器配置所需jar包-文档-xml配置-class类-maven-IDEA
class-dump-z全平台版本(linux、iPhone、Windows)
赠送jar包:classgraph-4.8.90.jar; 赠送原API文档:classgraph-4.8.90-javadoc.jar; 赠送源代码:classgraph-4.8.90-sources.jar; 赠送Maven依赖信息文件:classgraph-4.8.90.pom; 包含翻译后的API文档:class...
装载锁 加载锁定组件。 在加载时锁定元素并使用添加微调器。 安装 $ component install cristiandouce/loading-lock 应用程序接口 var loading = require ( 'loading-lock' ) ; 加载(el,选项) 使用选项返回...
class-un-loading.tar.gz
class-dump-3.5
classin-lms_win_install_4.2.10.119lms_s.exe