如何构造使用自定义的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本身所带有的。 
原文: http://www.onjava.com/pub/a/onjava/2005/01/26/classloading.htm  
 
  |