OFBiz 开发指南系列 Apache OFBiz Advanced Framework Hongs 收集整理 Contact:[email protected] 本人最近基于这套开源 ERP 架构开发了几个电子商务系统,感觉 这个架构功能强大,性能也非常好,所以打算整理出一套开发指南来, 希望更多的人能快速使用这套架构。我打算先把技术方面的先整理出 来,陆续可能会把数据模型也整理出来。 Java and J2EE The Java Classpath 轻松玩转Java配置的Classpath【转自www.bitsCN.com】 和Java类路径(classpath)打交道的过程中,开发者偶尔会遇到麻烦。这 是因为,类装载器实际装入的是哪一个类有时并不显而易见,当应用程序的 classpath包含大量的类和目录时,情况尤其严重。本文将提供一个工具,它能 够显示出被装入类文件的绝对路径名。 一、Classpath基础 网管联盟bitsCN_com Java虚拟机(JVM)借助类装载器装入应用程序使用的类,具体装入哪些类 根据当时的需要决定。CLASSPATH环境变量告诉类装载器到哪里去寻找第三方提 供的类和用户定义的类。另外,你也可以使用 JVM 命令行参数-classpath 分别 为应用程序指定类路径,在-classpath 中指定的类路径覆盖 CLASSPATH 环境变 量中指定的值。 网管网www_bitscn_com 类路径中的内容可以是:文件的目录(包含不在包里面的类),包的根目录 (包含已打包的类),包含类的档案文件(比如。zip 文件或者。jar 文件)。在 Unix家族的系统上,类路径的各个项目由冒号分隔,在MS Windows系统上,它 们由分号分隔。 网管网www_bitscn_com 类装载器以委托层次的形式组织,每一个类装载器有一个父类装载器。当一 个类装载器被要求装载某个类时,它在尝试自己寻找类之前会把请求先委托给它 的父类装载器。系统类装载器,即由安装在系统上的JDK或JRE提供的默认类装 载器,通过 CLASSPATH 环境变量或者-classpath 这个 JVM 命令行参数装入第三 方提供的类或者用户定义的类。系统类装载器委托扩展类装载器装入使用 Java Extension 机制的类。扩展类装载器委托自举类装载器(bootstrap class loader)装入核心JDK类。 网管bitscn_com 你可以自己开发特殊的类装载器,定制JVM如何动态地装入类。例如,大多 数Servlet引擎使用定制的类装载器,动态地装入那些在classpath指定的目录 内发生变化的类。 网管网www_bitscn_com 必须特别注意的是(也是令人吃惊的是),类装载器装入类的次序就是类在 classpath中出现的次序。类装载器从classpath的第一项开始,依次检查每一 个设定的目录和压缩文件,尝试找出待装入的类文件。当类装载器第一次找到具 有指定名字的类时,它就把该类装入,classpath中所有余下的项目都被忽略。 网管下载dl.bitscn.com 看起来很简单,对吧? 网管下载dl.bitscn.com 二、可能出现的问题 网管联盟bitsCN@com 不管他们是否愿意承认,初学者和富有经验的 Java 开发者都一样,他们都 曾经在某些时候(通常是在那些最糟糕的情形下)被冗长、复杂的 classpath 欺骗。应用程序所依赖的第三方类和用户定义类的数量逐渐增长,classpath也 逐渐成了一个堆积所有可能的目录和档案文件名的地方。此时,类装载器首先装 载的究竟是哪一个类也就不再显而易见。如果classpath中包含重复的类入口, 这个问题尤其突出。前面已经提到,类装载器总是装载第一个它在 classpath 中找到的具有合适名字的类,从实际效果看,它“隐藏”了其他具有合适名字但 在classpath中优先级较低的类。 网管下载dl.bitscn.com 如果不小心,你很容易掉进这个classpath的陷阱。当你结束了一天漫长的 工作,最后为了让应用程序使用最好、最新的类,你把一个目录加入到了 classpath,但与此同时,你却忘记了:在 classpath 的另一个具有更高优先级 的目录下,存放着该类的另一个版本! 网管联盟bitsCN@com 三、一个简单的classpath工具 优先级问题是扁平路径声明方法与生俱来固有的问题,但它不是只有 Java 的classpath才有的问题。要解决这个问题,你只需站到富有传奇色彩的软件巨 构的肩膀上:Unix 操作系统有一个 which 命令,在命令参数中指定一个名字, which就会显示出当这个名字作为命令执行时执行文件的路径名。实际上,which 命令是分析PATH变量,然后找出命令第一次出现的位置。对于Java的类路径管 理来说,这应该也是一个好工具。在它的启发之下,我着手设计了一个 Java 工 具JWhich。这个工具要求指定一个Java类的名字,然后根据classpath的指引, 找出类装载器即将装载的类所在位置的绝对路径。 下面是一个 JWhich 的使用实例。它显示出当 Java 类装载器装载 com.clarkware.ejb.ShoppingCartBean 类时,该类第一次出现位置的绝对路径 名,查找结果显示该类在某个目录下: > java JWhich com.clarkware.ejb.ShoppingCartBean Class 'com.clarkware.ejb.ShoppingCartBean' found in 网 管 下 载 dl.bitscn.com '/home/mclark/classes/com/clarkware/ejb/ShoppingCartBean.class' 下面是第二个 JWhich 的使用实例。它显示出当 Java 类装载器装载 javax.servlet.http.HttpServlet 类时,该类第一次出现位置的绝对路径名, 查找结果显示该类在某个档案文件中: > java JWhich javax.servlet.http.HttpServlet Class 'javax.servlet.http.HttpServlet' found in 'file:/home/mclark/lib/servlet.jar!/javax/servlet/http/HttpServlet.cl ass' 四、JWhich的工作过程 要精确地测定classpath中哪一个类先被装载,你必须深入到类装载器的思 考方法。事实上,具体实现的时候并没有听起来这么复杂——你只需直接询问类 装载器就可以了! 1: public class JWhich { 中国网管联盟bitsCN.com 2: 3: /** 4: * 根据当前的classpath设置, 5: * 显示出包含指定类的类文件所在 6: * 位置的绝对路径 7: * 8: * @param className <类的名字> 9: */ 10: public static void which(String className) { 11: 12: if (!className.startsWith("/")) { 13: className = "/" + className; 14: } 15: className = className.replace('.', '/'); 16: className = className + ".class"; 17: 18: java.net.URL classUrl = 19: new JWhich().getClass().getResource(className); 20: 21: if (classUrl != null) { 22: System.out.println("\nClass '" + className + 23: "' found in \n'" + classUrl.getFile() + "'"); 24: } else { 25: System.out.println("\nClass '" + className + 26: "' not found in \n'" + 27: System.getProperty("java.class.path") + "'"); 28: } 29: } 30: 31: public static void main(String args[]) { 网管联盟bitsCN@com 32: if (args.length > 0) { 33: JWhich.which(args[0]); 34: } else { 35: System.err.println("Usage: java JWhich "); 36: } 37: } 38: } 首先,你必须稍微调整一下类的名字以便类装载器能够接受(12-16 行)。 在类的名字前面加上一个“/”表示要求类装载器对 classpath 中的类名字进行 逐字精确匹配,而不是尝试隐含地加上调用类的包名字前缀。把所有“.”转换 为“/”的目的是,按照类装载器的要求,把类名字格式化成一个合法的 URL 资 源名。 接下来,程序向类装载器查询资源,这个资源的名字必须和经过适当格式化 的类名字匹配(18-19行)。每一个Class对象维护着一个对装载它的ClassLoader 对象的引用,所以这里是向装载JWhich类的类装载器查询。Class.getResource() 方法实际上委托装入该类的类装载器,返回一个用于读取类文件资源的URL;或 者,当指定的类名字不能在当前的 classpath 中找到时,Class.getResource() 方法返回null。 最后,如果当前的classpath中能够找到指定的类,则程序显示包含该类的 类文件所在位置的绝对路径名(21-24 行)。作为一种调试辅助手段,如果当前 classpath中不能找到指定的类,则程序获取java.class.path系统属性并显示 当前的classpath(24-28行)。 网管联盟bitsCN@com 很容易想象,在使用 Servlet 引擎 classpath 的 Java Servlet 中,或者在 使用EJB服务器classpath的EJB组件中,上面这段简单的代码是如何运作。例 如,如果 JWhich 类是由 Servlet 引擎的定制类装载器装入,那么程序将用 Servlet引擎的类装载器去寻找指定的类。如果Servlet引擎的类装载器不能找 到类文件,它将委托它的父类装载器。一般地,当 JWhich 被某个类装载器装入 时,它能够找出当前类装载器以及所有其父类装载器所装入的所有类。 【结束语】 如果需要是所有发明之母,那么帮助我们管理 Java 类路径的工具可以说迟 到了很长时间。Java 新闻组和邮件列表中充塞着许多有关 classpath 的问题, 现在 JWhich 为我们提供了一个简单却强大的工具,帮助我们在任何环境中彻底 玩转Java类路径。 【转自www.bitsCN.com】 CLASSPATH详解 设置类路径 结构 可通过对 JDK 工具使用 -classpath 选项(首选方法)或设置 CLASSPATH 环境变量来设置类路径。 C:> jdkTool -classpath path1;path2... C:> set CLASSPATH=path1;path2... 每个 path 以文件名或目录结尾,该文件名或目录取决于将类路径设置成什 么: 对于包含 .class 文件的 .zip 或 .jar 文件,路径以 .zip 或 .jar 文件 名结尾。 对于未命名包中的 .class 文件,路径以包含 .class 文件的目录结尾。 对于已命名包中的 .class 文件,路径以包含“root”包(完整包名中的第 一个包)的目录结尾。 用分号来分隔多个项目。使用 set 命令时,需要省略等号两边的空格(=)。 其中 jdkTool 可以为 Java、javac、javadoc,等等。有关详细列表,参见 JDK 开发工具。 说明 类路径告诉 Java 应用程序去哪里查找第三方和自定义类 -- 即不是 Java 扩展或 Java 平台一部分的类。在 JDK 1.2 中,JVM 和其他 JDK 工具通过依次 搜索平台库、库扩展和类路径来查找类(有关搜索策略的详细信息,参见如何查 找类)。 多数应用程序的类库都会充分利用扩展机制。因此,只有想要加载某个类库 (a) 未位于当前目录或其分枝包中 且 (b) 未位于扩展机制所指定的位置时,才 需设置类路径。 如果用户是从旧版本 JDK 升级而来,则启动设置可能包括不再需要的 CLASSPATH 设置。这时应该删除任何非应用程序特定的设置。有些使用 Java 虚 拟机的第三方应用程序可能修改 CLASSPATH 环境变量以包括它们使用的类库。 这种设置可以保留。 可通过在调用 JVM 或其他 JDK 工具时使用 Java 工具的 -classpath 选 项改变类路径(例如: java -classpath ...)。这是改变类路径的首选方法。 还可通过使用 CLASSPATH 环境变量改变类路径。 注意:JDK 1.2 缺省类路径是当前目录。设置 CLASSPATH 变量或使用 -classpath 命令行开关将覆盖缺省值,因而如果想要在搜索路径中包括当前目 录,则必须在新设置中包括“.”。 类可以存储在目录(文件夹)或归档文件(例如 classes.zip 或 classes.jar)中。有关归档文件的详细信息和类路径的工作原理,参见本文档 最后的理解类路径和包名。 重要说明:JDK 旧版本在缺省类路径中还包括 /classes 项。该目录仅供 JDK 使用,且不用于应用程序类。应用程序类应该放置在 JDK 外部的目录。这 样,安装新 JDK 时不必需要重新安装应用程序库。为了与旧版本的兼容性,使 用 /classes 目录作为类库的应用程序在当前版本中仍能运行,但不能保证在以 后的版本中它们还能运行。 使用 Java 工具的 -classpath 选项 Java 工具 java、jdb、javac 和 javah 具有 -classpath 选项,在工具运 行时它将取代缺省类路径或由 CLASSPATH 环境变量所指定的类路径。这是改变 类路径设置的推荐方法,因为这样每个应用程序可具有它所需的类路径而又不会 干扰其他应用程序。 运行时工具 java 和 jdb 还具有 -cp 选项。该选项是 -classpath 的缩 写。 对于非常特殊的情况,java 和 javac 都具有开关,使得可改变它们使用的 路径以查找它们自己的类库。但是,绝大多数用户从来都不会用到这些开关。 使用 CLASSPATH 环境变量 如前一节中所述,一般用户将想要使用 -classpath 命令行选项。本节将介 绍如何设置 CLASSPATH 环境变量或清除以前安装遗留下的设置。 设置 CLASSPATH 在 DOS 提示符下,可用 set 命令修改 CLASSPATH 环境变量。其格式为: set CLASSPATH=path1;path2 ... 路径应该以指定驱动器的字母开头,例如 C:\...。这样,在偶然切换到不 同驱动器时仍可找到类(例如,如果路径项以 \... 开头,并且当前位于驱动器 D: 上,则所需的类将在 D: 而不是 C: 驱动器上找)。 清除 CLASSPATH 如果 CLASSPATH 环境变量被设置成不正确的值,或启动文件或脚本程序设 置了不正确路径,则可通过使用下列命令清除 CLASSPATH: C:> set CLASSPATH= 该命令仅清除当前会话的 CLASSPATH。要确保在以后的会话中具有正确的 CLASSPATH 设置,则应该删除或修改启动设置。 更改启动设置 如果在系统启动时设置 CLASSPATH 变量,则查找它的位置取决于所使用的 操作系统: 操作系统 方法 Windows 98 和 Windows 95 检查 autoexec.bat 文件中的 set 命令。 Windows NT 启动“控制面板”,选择“系统”,单击“环境”选项卡,并 在“用户变量”部分中,检查 CLASSPATH 变量。 理解类路径和包名 Java 类被组织成包,而这些包被映射到文件系统中的目录。但是与文件系 统不同的是,无论何时指定包名,都应指定完整包名 -- 永远不要仅指定它的一 部分。例如,java.awt.Button 的包名总是应指定为 java.awt。 例如,假定想要 Java 运行环境在包 utility.myapp 中查找名为 Cool.class 的类。如果该目录的路径为 C:\java\MyClasses\utility\myapp, 则应该将类路径设置成包含 C:\java\MyClasses。 要运行该应用程序,可使用下述 JVM 命令: C:> java -classpath C:\java\MyClasses utility.myapp.Cool 当该应用程序运行时,JVM 使用类路径设置查找在 utility.myapp 包中定 义的任何其他类。 注意:应在命令中指定完整包名。例如,设置类路径包含 C:\java\MyClasses\utility 并使用命令 java myapp.Cool 是不可能的,因为 这找不到该类。 (您可能想知道用什么定义类的包名。答案是:包名是类的一部分,并且不 能修改,除非重新编译该类。) 注意:包规范机制一个有趣的结果是,属于相同包的多个文件实际上可存在 于不同的目录中。对于每个类,包名都是相同的,但是每个文件的路径可从类路 径中的不同目录开始。 文件夹和归档文件 当类存储在目录(文件夹)中时,例如 c:\java\MyClasses\utility\myapp, 则类路径项指向包含包名第一个元素的目录(在这里为 C:\java\MyClasses,因 为包名是 utility.myapp)。 但是当类存储在归档文件(.zip 或 .jar 文件)中时,类路径项则是该 .zip 或 .jar 文件的路径。例如,要使用位于 .jar 文件中的类库,则命令应该类似 下述形式: java -classpath C:\java\MyClasses\myclasses.jar utility.myapp.Cool 多重指定 要在目录 C:\java\MyClasses 和 C:\java\OtherClasses 中查找类文件, 则可将类路径设置为: java -classpath C:\java\MyClasses;C:\java\OtherClasses ... 注意两个路径之间用分号分隔。 指定次序 指定多个类路径项的次序是相当重要的。Java 解释器将按照目录在类路径 变量中的次序在各个目录中查找类。在上例中,Java 解释器首先在目录
Description: