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交付方式,是社会进一步精...

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

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

    GIS开发者-GIS学习的读物

    • 2011-09-08 22:12
    • 1.57MB
    • 下载

    iOS 申请开发者账号-总结

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

    Mac环境配置 - iOS开发者 -待续

    Mac 环境配置 显示所有文件夹 显示:defaults write com.apple.finder AppleShowAllFiles -bool true 隐藏:defaults write...
    内容举报
    返回顶部
    收藏助手
    不良信息举报
    您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
    举报原因:
    原因补充:

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