让classpath参数走开

转载请保留本行原始出处声明信息 : http://www.zeali.net/entry/337 MaDe1nZEAL
标签 ( JAVA/C++ ): classpath ,  classloader ,  源代码
对于Java开发人员(尤其是初学者)来说,因为classpath配置问题所导致的代码编译运行出错相当普遍,经验教训足可以 专文叙之。实际上,我们可以通过实现自定义的ClassLoader等方法来尽量避免classpath对于系统环境的依赖。

  通过加参数调用 javac,可以在编译时使用自定义的 ClassLoader 来完成类的定位加载:

javac -J-Djava.system.class.loader=my.ClassLoaderImpl theSource.java

  自定义 ClassLoader 的方式可以参考这里(基本上来说就是通过继承 findClass(String) 方法来使JVM按照自己期望的规则来加载类)。还处于beta阶段的 Mustang Java SE 6 据说将提供新的工具 javax.tools.JavaCompilerTool 来替代 javac ,这个全新的编译工具应该会给程序员更好的编译体验。

  大多数流行的 java IDE 都大大简化了对于 classpath 的配置过程,以至于很多在程序员的开发环境运行良好的代码发布之后才出现各种各样的问题。所以要想让程序包能够顺利的执行于产品环境,我们通常的做法是写一堆的 bat 或 shell 脚本来完成各种运行参数的配置。而这些大段大段的脚本当中,对 classpath 的配置占了相当大的比重。

  因此 Heikki Uusitalo 写了一个 BootLoader 类(原始代码似乎有些问题,这里修改了一下):将这个类作为引导程序去根据自定义的规则来加载所有必需的 jar 包等资源,然后再启动真正的 main 方法。把这个 BootLoader 类单独打包成一个 jar 文件,运行的时候只需要运行它即可。当然你可以根据实际情况修改读取的路径、规则等信息。

  1. import java.io.*;  
  2. import java.net.*;  
  3. import java.lang.reflect.*;  
  4.   
  5. public class BootLoader  
  6. {  
  7.   public static void main(final String[] args) throws Exception  
  8.   {  
  9.     // check that the lib folder exists  
  10.     File libRoot = new File(LIB_FOLDER);  
  11.     if(!libRoot.exists()) {  
  12.       throw new Exception("No 'lib' folder exists!");  
  13.     }  
  14.     // read all *.jar files in the lib folder to array  
  15.     File[] libs = libRoot.listFiles(new FileFilter()  
  16.     {  
  17.       public boolean accept(File dir)  
  18.       {  
  19.         String name = dir.getName().toLowerCase();  
  20.         return name.endsWith("jar") || name.endsWith("zip");  
  21.       }  
  22.     });  
  23.   
  24.     URL[] urls = new URL[libs.length];  
  25.     // fill the urls array with URLs to library files found in libRoot  
  26.     for(int i = 0; i < libs.length; i++) {  
  27.       urls[i] = new URL("file",null,libs[i].getAbsolutePath());  
  28.     }  
  29.     // create a new classloader and use it to load our app.  
  30.     classLoader = new URLClassLoader(urls,  
  31.                                      Thread.currentThread().  
  32.                                      getContextClassLoader());  
  33.     // get the main method in our application to bring up the app.  
  34.     final Method mtd = classLoader.loadClass(APP_MAIN_CLASS).getMethod("main",  
  35.         new Class[] {String[].class});  
  36.     // Using thread to launch the main 'loop' so that the current Main method  
  37.     // can return while the app is starting  
  38.     new Thread(new Runnable()  
  39.     {  
  40.       public void run()  
  41.       {  
  42.         try {  
  43.           mtd.invoke(null,new Object[] {args});  
  44.         } // forward the args  
  45.         catch(Exception e) {  
  46.           throw new RuntimeException(e);  
  47.         }  
  48.       }  
  49.     },"AppMain").start();  
  50.     // Give the app some time to start before returning from main.  
  51.     // This doesn't delay the starting in any way  
  52.     Thread.sleep(1000);  
  53.   }  
  54.   
  55.   private static final String LIB_FOLDER = "lib";  
  56.   private static final String APP_MAIN_CLASS = "com.my.application.MyTest";  
  57.   private static ClassLoader classLoader;  
  58. }  

猜你喜欢

转载自yzyzero.iteye.com/blog/1910847
今日推荐