Class Loading ---(类装载机制,开发者不得不知道的故事) --下篇

原创 2005年06月27日 01:18:00

如何构造使用自定义的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


资源文件:
Sample code for this article JDK 1.5 API Docs The Java language specification "Understanding Extension Class Loading " in the Java tutorial "Inside Class Loaders" from ONJava "Inside Class Loaders: Debugging" from ONJava "What version is your Java code?" from JavaWorld " Understanding J2EE Application Server Class Loading Architectures" from TheServerSide Byte Code Engineering Library Server-Based Java Programming by Ted Neward

原文:
http://www.onjava.com/pub/a/onjava/2005/01/26/classloading.htm

美团点评技术沙龙第14期:美团背后的故事-你不知道的美团云

美团点评技术沙龙由美团 · 大众点评技术团队主办,每期沙龙邀请美团 · 大众点评及其他互联网公司的技术专家分享来自一线的实践经验,覆盖各主要技术领域。云计算是一种全新的企业IT交付方式,是社会进一步精...

开发者最佳实践日-Spark-Ecosystem

  • 2015年09月22日 16:45
  • 2.82MB
  • 下载

苹果开发者站神游薄记 - 概述

苹果开发者站神游薄记 - 概述
  • sleks
  • sleks
  • 2015年12月05日 13:46
  • 1845

iOS 申请开发者账号-总结

简述 iOS 开发在国内已经发展好几年了,在进行 iOS 开发之前必不可少的一件事,就是申请开发者账号。 申请开发者账号后,就可以进入开发者中心下载 Xcode 编译器,并且配置开发者证书进行真机...
  • jacksBO
  • jacksBO
  • 2017年04月27日 19:23
  • 210

测试显示性能-基于Android M 开发者预览版

安卓官方文档的汉化越来越及时了,新出的Android M 开发者预览版的文档已经全部翻译完了https://developer.android.com/intl/zh-cn/preview/overv...
  • whorus1
  • whorus1
  • 2016年04月22日 11:14
  • 322

组件接口(API)设计指南[2]-类接口(class interface)

规则1:使用当前平台的描述用语或构架 一个最常见的API错误设计是使用外来的规则,API属于一个特定的平台和相关开发者生态系统。你不能使用任何其他不同平台的描述用语或构架,这会污染你当前的代码...

Swift3.0-类(class)

类 (class关键字)   !!!引用类型    类是对一些具有相同属性和方法的具体食物的抽象;对象是类的具体实现    类的对象是指针的引用,赋值也只是创建一个指针对象,指向同样的内存区域。而值拷...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Class Loading ---(类装载机制,开发者不得不知道的故事) --下篇
举报原因:
原因补充:

(最多只允许输入30个字)