滴滴香浓,意犹未尽—畅游Java世界(4)

2.IBM Visual Age for Java    IBM的软件可以用一个字来概括——牛!其体积庞大,功能众多,使用对象是整个开发团队,而设计目标则是搞定视野里能看到的一切!如果你使用的是一整套IBM解决方案(包括WebSphere应用程序服务器和DB2通用数据库),那么IBM Visual Age for Java将是你的不二选择。如果非要说它有什么缺点,那就是IBM使用自己的JDK,而且目前的版本比较低,但是IBM所提供的却是完整的解决方案,你还用选择其它的么?相关网站http://www.ibm.com/software/vajava/。    3.WebGain Studio 4 with VisualCafé    正如你所知,VisualCafé本是Symantec公司的著名产品,只不过前些时候已经转让给了WebGain。但你不必对VisualCafé的未来有所担心,VisualCafé仍然起到了全功能Java开发工具的作用,而WebGain则增加了对Enterprise JavaBean(EJB)和基本UML图表设计的支持。同样,它绝佳的应用程序服务器搭配还是WebLogic。相关网站http://www.webgain.com/。    4.Forte for Java    作为Java技术的发明人和最主要的支持者,Sun公司还同时推出了大量的Java开发工具,Forte for Java就是Sun在放弃JavaWorkers后力推的IDE,它将调试器和用于Web应用开发系统的数据库组件整合到了统一的安装环境中。相关网站http://www.sun.com/forte/。    5.Oracle Internet Developer    尽管这种工具只能针对Oracle数据库使用,而且还施加了这一限制,但开发人员仍然可以从中获得相当强大的中间层功能和采用JSP的Web应用程序开发能力。相关网站http://www.oracle.com/ip/develop/ids/index.html?jdeveloper.html。    Java学习资源    1.网站    Java的相关网站很多,但遗憾的是优秀的中文站点很少。最简便的Java资源网站寻找方法就是在各类搜索引擎中使用Java以及其它有关的关键字来查找,下面我还是推荐几个“重量级”的,如果能够认真学完任何一个中的内容,你一定已经成为一个Java高手了。    http://java.sun.com/    Sun的Java中心,标准的JDK就是在这里下载。    http://www.cn.ibm.com/developerWorks/java/    IBM的Java技术专区,难得的优秀Java中文站点。    http://www.javaworld.com    IDG的Javaworld网站。    http://www.microjava.com/    嵌入式Java的专门站点。    http://www.jspinsider.com/    专注于JSP的站点。    http://www.sys-con.com/java/index2.html    著名Java杂志《Java Developer‘s Journal》的网站。    2.书籍    《Java2 核心技术》卷Ⅰ:基础知识 卷Ⅱ:高级特性    机械工业出版社    这是Sun公司的推荐图书,已经是第四版了。厚厚的两本囊括了Java编程的大多数常用知识,作者的开发功底相当深厚,深入浅出、旁征博引,教给大家的不仅仅只是Java编程,甚至体现了Programming的精髓,无论是初学者还是进阶者,它都是必备的一套好书(多说一句,机械工业出版社的书籍翻译不错,错字也少)。    《Java编程思想》(《Thinking in Java》)    机械工业出版社    不要怀疑,这就是名著《Thinking in C++》的作者写的,没什么可犹豫的,一定要找一本来看看。    《Enterprise JavaBeans》    中国电力出版社    O‘Reilly同名英文书第二版的中文版,论述EJB的专著。几乎每一本O‘Reilly的技术书籍都是同类 中的佼佼者(就像从前的《TCP/IP Network Administration》、《DNS and BIND》、《Programming Perl》等),这本同样也不例外,如果你对EJB特别感兴趣,不要错过这本少有的此类中文书籍。    后记    本来想写成一个Java初学者的指导,没想到才刚刚开始就发现大大超出了预计的版面……Java的应用确实太广泛,其体系也太过庞大,要想在短短几页之中完整的描述简直是不可能的。因此,我也就此打住,虽然还留下了诸如JDBC类型、Java数据库、Java应用程序服务器、JXTA等等众多的内容,但所幸Java的总体架构已经基本说明,剩下这些就留给大家在实践中逐渐掌握吧。 滴滴香浓,意犹未尽—畅游Java世界(1) 滴滴香浓,意犹未尽—畅游Java世界(2) 滴滴香浓,意犹未尽—畅游Java世界(3) 滴滴香浓,意犹未尽—畅游Java世界(4) <

小小豆叮

JDBC 文档页

<

小小豆叮

Waba -- 嵌入式Java程序开发的另类选择

蒋清野 (qjiang@tsinghua.edu)
美国导航与控制公司
2001 年 10 月

本文介绍了一个目前在国内尚未广为人知的嵌入式Java程序开发工具--Waba。 Waba是一个专门为嵌入式系统设计的Java语言的子集,利用Waba能够为手机、个人 数字助理、掌上型电脑、多功能计算器等多种便携式设备开发应用程序。目前版本 的Waba虚拟机支持的平台包括AmigaOS, BeOS, Linux, MacOS, MS-DOS, Newton, OS/2, PalmOS, Windows 和Windows CE。在本文中作者将全面介绍Waba平台、开发 工具以及Waba相关资源。

Waba平台介绍
Waba是一种专门为微小型设备设计的程序开发平台,在该平台上定义了一种程 序设计语言,一个虚拟机,一种类库文件格式以及一组基本类库。由于Waba语言的 语法是Java语言的语法的严格子集,Waba平台的类库文件格式也是Java平台类库文 件格式的严格子集,因此熟悉Java的开发人员能够利用自己已经熟悉的Java开发平 台进行Waba程序开发。

Waba平台所针对的是例如手机、个人数字助理、掌上型电脑、多功能计算器等 硬件资源非常紧张的微小型设备。因此,Waba的编程语言、虚拟机和基本类库都针 对微小型设备进行了优化处理。在Java语言中需要耗费大量内存或者是被认为与微 小型设备无关的特性均被排除在Waba平台之外。同样,Waba平台也对Java平台的基 本类库进行了大幅度裁减,从而使得Waba平台只需要占用很少的硬件资源而仍然能 够满足微小性设备应用程序设计的需要。

和Java应用程序相类似,Waba应用程序能够在任何安装了Waba平台的操作系统 上运行。最早的Waba平台是针对Windows CE操作系统进行开发的,但是目前Waba虚 拟机已经被移植到多种平台上,其中包括AmigaOS, BeOS, Linux, MacOS, MS-DOS, Newton, OS/2, PalmOS和Windows。就我所了解的情况,目前支持DOS的Java虚拟机 只有KaffePC 和Waba,两者均要求Intel 386以上的中央处理器,但是KaffePC需要 8 MB的内存(推荐配置是16 MB),而Waba仅仅需要4 MB或者是更少的内存。Psion也 与前段时间宣布开发支持MS-DOS的Java虚拟机,但是其测试版本至今尚未发布。前 段时间Waba又推出了专门为T1计算器设计的虚拟机,这是目前仅有的一个专门为计 算器设计的Java虚拟机。

为了保持与Java平台的兼容,Waba提供了一系列过渡类库使得Waba应用程序也 能够在仅仅任何安装了Java运行环境的平台上运行。它既可以是Windows或者UNIX 下面的普通应用程序(Application),也可以是内嵌在浏览器中的一个小应用程序 (Applet)。

与其他嵌入式应用程序开发环境相比较,Waba平台具有如下优点:

  1. 由于Waba本身是为硬件资源非常紧张的微小型便携式设备设计的,Waba虚 拟机所要求的存储空间通常都小于64 K,其中包括基本类库,基于Waba的应用程序 在运行时刻仅仅要求少于10 K的内存。
  2. Waba所提供的基本类库事先封装了大量在嵌入式系统中常见的功能,因此 开发人员能够在这些事先经过严格测试的基本类库的基础上迅速开发自己的应用程 序。同时,Waba所支持的平台非常广泛,为一个平台所开发的应用程序不需要经过 任何修改即可以在另一平台上运行。
  3. 微小型便携式设备通常没有任何外界存储设备,如果应用程序对内存进行 了非法操作,用户必须重新启动该设备,从而导致不可挽回的数据丢失。作为Java 的一个严格子集,Waba同样限制用户应用程序直接对内存进行操作,从而避免了由 于对内存进行非法操作而导致的系统崩溃和数据丢失。此外,Java语言特有的垃圾 回收功能(Garbage Collection)减少了在应用程序中发生内存泄露(Memory Leak) 的可能性。

Waba开发工具
在一个Waba应用程序的开发过程中,开发人员需要一个针对目标平台的Waba虚拟机,一套Waba开发环境,以及一个测试环境。

Waba虚拟机:Waba虚拟机已经被移植到多种平台上,其中包括AmigaOS, BeOS, Linux, MacOS, MS-DOS, Newton, OS/2, PalmOS, Windows和Windows CE。Waba虚 拟机的源代码是开放的,开发人员可以根据自己的需要对Waba虚拟机进行裁剪或者 是修改。

Waba开发环境:WabaSoft提供了一个软件开发工具包(Software Development Kit),称为WabaSDK 。这个工具包提供了所有的Waba基本类库,开发人员可以将这 些基本类库添加到自己熟悉Java开发环境中去,然后在自己熟悉的Java开发环境中 进行Waba应用程序开发。一个最基本的Waba开发环境是JavaSDK + WabaSDK, 开发 人员需要利用JavaSDK中提供的javac来编译Waba应用程序。此外,WabaSDK 还提供 了针对PalmPilot和Windows CE 的代码转换工具ExeGen和Warp,利用这两个工具开 发人员能够将编译以后的Waba类库文件转换成PalmPilot或者是Windows CE 可以识 别的可执行文件。WabaSDK 的源代码同样是开放的,开发人员可以根据需要对其进 行裁剪和修改,或者是将其移植到自己的开发平台上。

随着Waba平台在嵌入式系统中的广泛应用,专门为Waba设计的集成开发环境也 不断的涌现出来,VisualWaba和UIGen 可以说是这些第三方集成开发环境中的佼佼 者。VisualWaba和UIGen 本身都是利用Java开发的应用程序,用来进行应用程序开 发似乎有点反应迟钝,但是如果综合考虑一下Borland JBuilder和IBM Visual Age for Java的性能,VisualWaba和UIGen 的速度还是可以容忍的。相对来说UIGen 的 功能还比较弱,只能够根据用户设计的界面生成相对应源代码。VisualWaba更类似 于微软的Visual Basic,开发人员不但能够在其中进行界面设计和程序设计并生成 源代码,还能够对程序进行编译和调试,最后生成PalmPilot 或者是Windows CE平 台上的可执行代码。

除了VisualWaba和UIGen 以外,还有另外一些由第三方开发的工具。这些工具 或者为Waba提供一些专门的类库,或者是增强Waba的图形用户界面。例如MathFP为 Waba提供了高性能的符点运算类库,使得Waba在没有数学协同处理器的情况下也能 够进行高性能的符点运算。mWaba AWT Toolkit 为Waba提供了类似于Java AWT的图 形用户界面功能。Waba GUI Library为Waba提供了更加强大的串口通讯、图形用户 界面以及HTML解析功能。

测试环境:在嵌入式便携式设备应用程序设计中,经常需要将生成的可执行代 码上载到目标平台上进行调试和测试。例如开发一个针对Windows CE的应用程序, 开发人员通常需要预先在桌面计算机上进行程序开发和编译,然后通过微软的便携 式设备服务程序将可执行代码上载到目标平台,最后在目标平台上进行调试,整个 过程非常的繁琐。在Waba中提供了一款针对Windows CE的模拟器,使得开发人员能 够在桌面计算机上直接调试应用程序,从而大大的减轻了开发人员的负担。

相关资源

  1. WabaSoft (http://www.wabasoft.com)

    WabaSoft是Waba的大本营,从该网站可以获得关于Waba平台的最新消息,并且可以下载各种版本的Waba开发工具以及相关文档。

  2. Waba Workbench (http://www.wabaworkbench.com)

    Waba Workbench是由Ed Crandell 创办的一个专门用于Waba技术交流的网站,该网站提供了一系列关于Waba开发的技术文章、扩展类库以及虚拟机。在这里也可以找到指向其他Waba技术网站的连接。

  3. Visual Waba (http://www.dmic.fr/palm/prg2.htm)

    VisualWaba的主页,从该网站可以获得关于VisualWaba的最新消息,并且可以免费下载VisualWaba的试用版以及相关文档。

  4. UIGen (http://home.c2i.net/badeand/UIGen/)

    UIGen的主页,从该网站可以获得关于UIGen的最新消息,并且可以在浏览器上直接利用UIGen 进行图形用户界面并且生成相对应的源代码。如果你需要经常性的使用UIGen的话,你需要将UIGen下载并安装在你的开发平台上。虽然UIGen 的用户界面非常简单,你还是可以在该网站上找到一个比较具体的用户指南。

  5. 其他网络资源

    http://www.superwaba.org/
    http://www.wabajump.org/
    http://www.cygnus.uwa.edu.au/~rnielsen/wextras/
    news://news.massena.com/pilot.programmer.waba
    news://news.falch.net/pilot.programmer.waba

结论
本文全面介绍了专门为嵌入式系统设计的Waba平台、开发工具以及Waba相关资 源。该平台支持包括AmigaOS, BeOS, Linux, MacOS, MS-DOS, Newton, PalmOS 和 Windows CE等一系列嵌入式操作系统,能够在手机、个人数字助理、掌上型电脑、 多功能计算器等多种便携式设备上运行。现有的Waba开发工具使得开发人员能够在 一般开发平台上设计、编译和调试针对便携式设备等目标平台的应用程序,能够大 大缩短嵌入式应用程序的开发周期。目前Waba平台已经在嵌入式应用程序设计领域 得到了广泛的应用,是一个优秀的嵌入式应用程序平台。

关于作者
蒋清野,软件工程专家。1999年7月获得清华大学学士学位,2001年1月获得伊里诺大学(Univ. of Illinois at Urbana-Champaign)硕士学位,目前是美国导航与控制公司(American GNC Corporation)工程专家。主要研究领域包括遥感图像信息处理,GPS应用,惯性导航,无线通讯和高速网络技术。电子邮件:qjiang@tsinghua.edu。
<

小小豆叮

WabaSoft

<

小小豆叮

配置Web应用环境实现JSP留言簿

Java Server Page(简称JSP),和ASP、PHP一样都是网络编程语言,只不过在JSP页面中插入的脚本代码是Java语句片段。要利用JSP编写应用,首先,必须要有一个能执行JSP脚本的Web服务器,可以在原有的Apache、IIS或PWS服务器的基础上建立,不过有许多技术上的问题。建议刚接触JSP的虫们,还是白手起家,直接安装一个专门支持JSP的Web服务器,以免节外生枝,这里给大家介绍的是Tomcat 3.1。 熟悉网络编程的人都知道,在网络编程中要是没有数据库的支持,一件很简单的事做起来都是相当的辛苦。那么在Java环境下使用什么数据库比较好呢?目前,流行的网络数据库主要有Oracle、Sybase、SQL Server、MySQL等,不过最适合个人网站或小型网络使用的首推MySQL,其完全免费、容易安装、容易管理、容易获得、完全支持SQL语言等特点,为目前广大网络编程爱好者所喜欢。本文介绍一下在Windows环境下如何安装Java SDK、Tomcat、MySQL、JDBC for MySQL。 软件准备 首先要下载到下面这些程序: 1、java编译支持环境:j2sdk1_3_-win.exe(30MB) 2、JDBC for MySQL驱动程序:mm.mysql.jdbc-1.2b.zip(386KB) 3、支持JSP的Web服务器Tomcat3.1:jakarta-to,cat.zip(2.23MB) 4、MySQL数据库存服务器:mysql-3.23.21-beta-win-src.zip(2.23MB) 以上程序除MySQL数据库存服务器外,在http://java.sun.com/中都有最新版的程序,在各大下载中心也都很容易下载到。 安装具有JDBC for MySQL的JSP开发环境 安装Java 开发工具包 在用户访问Tomcat服务器的JSP页面时,Tomcat首先调用Java开发工具包,编译并执行JSP页面中的Java代码,将结果以HTML的格式返回给客户。因此在安装Tomcat之前,必须先安装Java开发工具包。安装时直接双击下载的j2sdk1_3_0-win.exe,就可以安装Java开发环境,惟一需要操作的就是选择一下安装目录,这里假设安装在C:\JDK1.3目录下。 另外, 如果选用中文的Windows,必须修改系统注册表,因为在安装过程中,系统用中文注册“Java 运行时环境”这一分支,该分支用于指明Java运行时所需文件的目录,而Java SDK不能识别系统注册表中的中文数据。 具体步骤是:用RegEdit打开注册表并找到Javasoft项, 位置为:hkey_local_machine→software→javasoft,找到 “Java 运行时环境” ,把这个分支导出到文件1.reg中。然后用文本编辑器打开1.reg,把其中的所有“Java 运行时环境”替换成“Java Runtime Environment”并保存,双击该文件导入注册表。 接着是设置环境变量。在Win 9x中,要编辑Autoexec.bat文件,用Set 语句来设定环境变量。在Win NT或Win 2000中可以选择“我的电脑”,右键点出选单,选择“属性”,弹出“系统特性”对话框, 选择“高级”,然后点按钮“环境变量”,就可以编辑系统的环境变量了。 在其中加入如下语句: rem 设置路径 PATH=%PATH%;c:\jdk1.3;c:\jdk1.3\bin rem 设置java环境变量 set CLASSPATH=C:\jdk1.3\lib\Tools.jar;C:\jdk1.3\lib\dt.jar; rem 设置java主目录 set JAVA_HOME=c:\jdk1.3 安装Tomcat 3.1 安装Tomcat 3.1比较简单,直接把jakarta-tomcat.zip解压释放到C:\Tomcat目录下即可,接着是设置环境变量,加入如下语句: rem 设置路径 PATH=%PATH%;c:\tomcat rem 设置tomcat环境变量 set CLASSPATH=c:\tomcat\classes;c:\tomcat\lib;%CLASSPATH rem 设置TOMcat的主目录 set TOMCAT_HOME=c:\tomcat 重新启动电脑后,你就拥有了一台支持JSP的Web服务器。运行C:\Tomcat\Bin目录下Startup.bat后出现两个命令行方式的窗口。这时在浏览器中键入 http://localhost:8080/,应该可以看到Tomcat 3.1的画面了。对了,千万不要把这两个窗口关了,它表示是Java和Tomcat正在后台运行。要关闭服务器可执行C:\Tomcat\Bin目录下Shutdown.bat。 安装MySQL数据库管理系统 将下载的mysql-3.23.21-beta-win-src.zip解压缩到一个临时目录,运行临时目录中的Setup,根据安装向导选择好安装目录和安装方式,系统就会完成安装。这里假设安装在C:\MySQL目录下。运行C:\MySQL\Bin\目录下的mysqld-shareware.exe就可以启动MySQL了。启动MySQL后,Windows桌面没什么变化,可以通过执行MySQL Manager来检查数据库服务是否安装成功。如果安装成功,你就可以直接打开里面的库Test和MySQL。 安装JDBC for MySQL 为了使Java能操作MySQL的数据库,需要安装MySQL的JDBC驱动程序,将mm.mysql.jdbc-1.2b.zip解压到C:\下,自动生成一个mm.mysql.jdbc-1.2b的目录,并设置环境变量: rem 设置mysql.jdbc环境变量 set CLASSPATH=c:\mm.mysql.jdbc-1.2b;%CLASSPATH 重新启动后,所有的安装就全部OK了! 例子:使用环境建立留言簿 建立存放数据的表 要设计一个留言簿,首先必须在MySQL的数据库中建立一个存放留言数据的表,假设该表为Questbook,其结构如下: Recordid 存放记录号 name 存放留言者的姓名 Email 存放留言者的邮件地址 body 存放留言者的留言 具体操作步骤: 1.执行程序mysqld-shareware.exe,启动MySQL。 2.执行程序MySQLManager,打开库Test。 3.选择Tools选单下的SQL Query ,出现MySQL Query窗口。 4.在Query标签下,输入命令如下:create table questbook(Recordid int,Name char(20),Email char(30), Body text)。 5.单击运行图标。你就可以得到用于存放留言簿数据的表Questbook。 编写留言簿程序 Java是通过JDBC for MySQL提供的工具包中的API函数,来调用MySQL的数据库,你可以用浏览器打开C:\mm.mysql.jdbc-1.2b\doc\apidoc\index.html文件来获得所有API函数说明。下面我只向大家介绍几个编写留言簿所需的函数。 Class.forName("org.gjt.mm.mysql.Driver"); 用于加载 mm.mysql驱动程序 con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?user=root;password="); 用于连接本地数据库MySQL stmt = con.createStatement(); 生成数据库对象 rs = stmt.executeQuery("SELECT * FROM guestbook");执行SQL语句并返回结果集 将程序编好后放在Tomat的发布目录C:\Tomcat\webapps\ROOT下就可以了。 <

小小豆叮

Jive源代码 v1.2.4

<

小小豆叮

免费数据库清单

<

小小豆叮

滴滴香浓,意犹未尽—畅游Java世界(1)

随着网络与移动办公逐渐走入平常人家的生活,Java由于其先天的优势在网络和嵌入设备应用程序的开发中已经“火”起来,国内学习Java编程的人也越来越多。但纵观市面上流行的各类Java学习书籍,讲解Java编程的优秀书籍不少,可是从宏观上描述Java的复杂分类、多方面应用、以及学习资源的却几乎没有。笔者并不是专业的Java程序员,因此也不敢探讨什么Java编程技术,只是将自己学习Java后所了解的一些基本概念及学习资源介绍给大家,相信对初学者理清思路、确定自己的发展方向也该有些帮助,万望高手勿笑。    从哪里来    James Gosling绝对没有想到,十年前他领导的小组为消费类电子产品(如机顶盒、全能烤箱等)所设计的计算机语言,在今天以及将来会有如此强大的生命力和广阔的应用前景。    由于最初的应用是那些功能和内存均不充分的嵌入设备,同时还要面对不同厂商产品所用的不同CPU,因此这种语言的设计要求不仅需要尽可能小且紧凑,而且更重要的是绝对不能受限于任何一种体系结构。这个项目在Sun公司内部的代号是——Green。当时,James Gosling在自己办公室的窗外看见了一棵橡树,所以他将这个新语言命名为Oak。    当交互电视成为一项利润巨大的产业时,Sun希望Oak能成为赚钱策略的一部分,可惜这个愿望至今都还没有实现。正当Sun决定放弃Oak的开发并将其开发人员分散到其它部门的时候,Web网出现了。一个偶然的机会,技术人员发现Oak语言很适合用在互联网上,于是Sun的开发人员设计了一个使得程序能够在Web页面上安全运行的方法,并为Oak换了一个更容易记住的名字——Java。就这样,随着互联网爆炸式的发展,Java现在已经成为可以胜任小到智能卡、大到企业级应用等各种开发任务的网络语言。    Java的应用定位    很高兴你能够看到这里,也证明了你对Java确实有一定的兴趣,因此我也不多说Java的好处,大家只需要明白Java这种应用广泛的网络编程语言来源于C/C++,并且更简单、安全,“Write once,run anywhere”这也是Java的招牌口号。    可惜目前国内的Java应用确实太少了,甚至很多人还不能区分Java和JavaScript,更无法去想象和领略到CORBA、Application Server、EJB、JSP、Servlet、XML等等的真正应用,也许很多人目前还认为Java仅限于在网页上显示一下会滚动的文字、水中倒影、或者就是聊天室……    按照Sun的定义,Java主要在以下三个方面发展:    Java 2 Standard Edition(J2SE)定位于客户端程序的应用; 滴滴香浓,意犹未尽—畅游Java世界(1) 滴滴香浓,意犹未尽—畅游Java世界(2) 滴滴香浓,意犹未尽—畅游Java世界(3) 滴滴香浓,意犹未尽—畅游Java世界(4) <

小小豆叮

SUN的JDBC学习中心

<

小小豆叮

西门子演示无线 Java技术

随着高速线路交换数据(HSCSD)和通用分组无线业务(GPRS)等传输技术被广泛应用,手机用户可以在户外随时随地、快捷可靠地存取无限量信息。另一方面,由于手机用户希望可以通过不同类型的应用软件来突显个人风格,因此市场对具弹性及灵活性的个人化服务的需求亦日趋强烈。无线Java平台的诞生正配合了这一市场需求,不仅将全面推动无线通讯的发展,更为手机供应商、网络运营商、内容供应商带来广阔的发展空间,同时为手机用户带来更多的选择和开辟广阔的自主空间。 无线 Java是专为手持设备而设的技术,它通过为手机建立一个通用、开放、标准的应用平台,让手机用户、内容供应商及网络运营商享有更大的自由度和自主空间。Java 平台能够配合现有的技术,并发挥辅助和强化的支持作用,使各项应用程序可以高效和可靠地运行。无线Java的主要优势在于: 应用和服务可以动态传输 利用无线Java手机,用户能安全地下载各种用无线Java语言编写的互动程序。目前,多家移动设备生产商及电子游戏生产商都在开发支持无线Java的产品,用户不仅可以通过无线上网接收电邮、收发传真、进行网上交易,还能及时下载更富动感的游戏。 具有跨平台兼容性 以无线Java编写的应用程序,无需重新编写便能应用在不同设备上(如手机、电子记事簿和电脑等),甚至能兼容于不同的网络协定。 进一步增强用户的使用体验 无线Java具有开放的应用环境,能支持更好的界面以及更高速的互动应用,可以鼓励开发人员编写图像更丰富、互动性更强、速度更快的应用程序,用户由此可以体验到更先进、更富刺激性的应用程序。有了GPRS技术的支持,这个特点将更为明显。 能支持离线作业 在离线状态下或在网络的覆盖范围以外,用无线Java编写的应用程序仍然能够在手机中运行,例如下载到手机上的无线Java游戏都能在离线环境下使用,并在稍后时间进行同步更新。 具有保密性 用无线Java编写适用于TCP/IP的应用程序,简单易行,此举能大大减省互联网协定与无线网络间的协定转换程序,而保安系统遭破坏的可能性亦随之降至最低,将无线世界的安全性提高到新的高度。 西门子一直与应用软件开发商和网络运营商保持紧密合作,致力把无线 Java 技术带到手机市场。另外,西门子亦与Java的始创开发商太阳微系统(Sun Microsystems)建立长远的伙伴合作关系,以保持西门子在这一技术领域的领先地位。展会期间,西门子专门召开无线Java介绍会,现场演示了Java技术在西门子手机中的应用。■ <

小小豆叮

Tomcat - 简明用户手册

这份文档提供了关于Tomcat的一些基本信息,内容如下所示: 1.Tomcat编译版本的安装. 2.被Tomcat使用的批处理文件的内容的说明。 3.关于server.xml文件(Tomcat的主要配置文件)的内容的说明 4.如何让Tomcat与本地的Web服务器协同工作。 5.如何将Tomcat部署在一个真正的网站上。 GETTING STARTED Tomcat 是一种有JSP环境的Servlet的容器。Servlet容器是代替用户管理和调用 Servlet的运行时外壳。 Servlet容器可以粗略的划分成下面几类: 1.独立的servlet容器 独立的servlet容器Web服务器的一部分。当使用一个以Java为基础的Web服务器时就是这种情况, 例如是JavaWebServer的一部分的servlet容器。独立的Servlet容器是被Tomcat使用的缺省方式。 然而,大多数站点服务器都不是以Java为基础的,这就把我们带领导到下一两种容器类型。 2. 集成到进程中的(In-process) servlet 容器 这种servlet容器和是把Web服务器的plugin和Java容器的实现结合在一起。 Web服务器的plugin在站点服务器的地址空间的内部打开一个JVM并且让Java容器在其中运行。 如果某一个请求(Request)要求执行Servlet,那么plugin就会接管这个请求并将它传递给 Java容器(使用JNI)。这种集成到进程中的很适合多线程单一进程的服务器,而且具有很好的性能。 但是伸缩性不好。 3.未集成到进程中的(Out-of-process) servlet 容器 这一类servlet容器也是将Web服务器的plugin和JVM中运行的的Java容器的实现结合在一起, 但它是在Web服务器的外部运行的。Web服务器plugin和Java容器JVM使用某种IPC机制(通常是TCP/IP Socket)进行通信。 如果某一个请求(Request)要求执行Servlet,那么plugin就会接管这个请求并将它(使用IPC)传递到Java容器。虽然这一类Servlet容器的反应时间比不上集成进线程的Servlet容器,但是在很多方面(可伸缩性、稳定性,等等)都要好于上一类。 Tomcat能被用作一个独立的容器(主要是用来开发和调试),或者当作一个已经存在的Web服务器 (目前支持阿帕奇,IIS和Netscape服务器)的一个附加软件(add-on)。 这意味只要你部署Tomcat你就不得不决定如何使用它;同时,如果你选择选择2或者3, 你还将需要安装Web服务器软件。 Tomcat和 Jserv之间的区别是什么? Tomcat==Jserv,不是吗? 这是一种普通的误解。Jserv是被建立为与阿帕奇一起使用的Servlet API 2.0兼容的容器。 Tomcat是完全重写并且兼容Servlet API 2.2和JSP 1.1的一种容器。 Tomcat使用了一些Jserv的代码,尤其是Jserv的阿帕奇服务器适配器(adapter), 但是相似的地方仅此而已。 我应该如何安装Tomcat的编译版本? 很简单. 你应该这样做: 由下面的地址下载 zip/tar.gz/无论什么(whatever) 文件 http://jakarta.apache.org/downloads/binindex.html. 当然是jakarta-tomcat.zip或jakarta-tomcat.tar.gz。 将下载的文件解压缩到某个目录 (例如 foo)。这将会创建一个叫做"tomcat"的新的子目录。 把当前目录改变成为“tomcat”并且设置新的环境变量(TOMCAT_HOME),使它指向你的tomcat所在的目录。 在 Win32 系统中你应该键入: "set TOMCAT_HOME=foo\tomcat" 在 UNIX 系统中你应该键入: for bash/sh "TOMCAT_HOME=foo/tomcat ; export TOMCAT_HOME" for tcsh "setenv TOMCAT_HOME foo/tomcat" 设置环境变量 JAVA_HOME ,使其指向你的JDK所在的目录,然后将Java解释器所在的路径添加到你的Path 环境变量中。 for Example: 在Win98下,键入set JAVA_HOME=C:\jdk1.3\ set PATH=c:\jdk1.3\bin;%PATH% 在Win NT下,环境变量的设置应该在 控制面版>系统>环境 中设置 That's it! 你现在就可以执行Tomcat,它将作为独立的Servlet容器(类型 I)来运行。 启动和停止 Tomcat 你可以用tomcat/bin目录中的批处理文件来启动Tomcat。 启动Tomcat: 在 UNIX 下: bin/startup.sh 在 Win32下 : bin\startup 停止 Tomcat: 在 UNIX 下: bin/shutdown.sh 在 Win32下: bin\shutdown Tomcat 目录的结构 假设你已经将 Tomcat 的编译分发版本(binary distribution)解压缩(unzipped/untared)了, 你应该的到下表中所示的目录结构: 目 录 名 描 述 bin 包含启动和停止...批处理文件(scripts)。 conf 包含设置部署在Tomcat上的Web应用的变量的初始值的设置文件,包括 server.xml (Tomcat 的主要配置文件) 和 web.xml doc 包含关于Tomcat的各种各样的文档。 lib 包含被Tomcat使用的各种各样的jar文件。在UNIX上,任何这个目录中的文件将被附加到Tomcat的classpath中。 logs Tomcat的log文件。 src servlet API的源文件。 但是别激动,呵呵,这些仅仅是应该被任何servlet容器执行的空的接口和抽象类别。 webapps 包含一些Web应用的例子 另外你可以,或者Tomcat会自动建立下列的目录: WORK 由Tomcat自动生成,这是Tomcat放置它运行期间的中间(intermediate)文件(诸如编译的JSP文件)地方。 如果当Tomcat运行时,你删除了这个目录那么将不能够执行包含JSP的页面。 CLASSES 你可以建立这个目录以把附加的类增加到classpath中。你放到这个目录中的任何类都将会出现在Tomcat的classpath中。 Tomcat的批处理(Scripts)文件 Tomcat是一个Java程序,因此在设置若干环境变量之后,从命令行执行它是可能的。 然而,通过设置手工Tomcat用到每一环境变量和使用命令行参数来调用Tomcat是容易出错和乏味的工作。 所以,Tomcat开发组提供了一些批处理(scripts)文件来使启动的和停止Tomcat更加容易。 注意:批处理仅仅是一种方便的启动和停止Tomcat的方法... 。你可以修改他们以定制自己的CLASSPATH,环境变量(诸如PATH和LD_LIBRARY_PATH等等),但要确保生成的命令行是正确的。 这些批处理文件都是什么? 下列的表格中列出了对普通的用户是最重要批处理文件: 批处理文件 描 述 tomcat 主要的Tomcat批处理文件。用来设定正确的环境,包括的CLASSPATH,TOMCAT_HOME和JAVA_HOME,并且用适当(proper)的命令行参数启动Tomcat。 startup 启动Tomcat(Starts tomcat in the background)。 "tomcat start"的快捷方式。 shutdown 停止Tomcat。 "tomcat stop"的快捷方式。 对用户来说,最重要的一个批处理文件是 tomcat(tomcat.sh/tomcat.bat)。其他和Tomcat 相关的批处理文件仅仅是作为一种简单的单任务的指向Tomcat批处理文件的一种转向(放置不同的命令行参数等等)。 (simplified single-task oriented entry point to the tomcat script) 更进一步分析 tomcat.sh/tomcat.bat ,它执行以下操作: 操作系统 行为 Unix 如果TOMCAT_HOME未被指定,猜想TOMCAT_HOME是什么. 如果JAVA_HOME未被指定,猜想JAVA_HOME是什么. 设置一个包含如下信息的 CLASSPATH - ${TOMCAT_HOME}/classes 目录 (如果可用). ${TOMCAT-HOME}/lib中的所有内容。 ${JAVA_HOME}/lib/tools.jar (这个jar文件包含工具javac,我们需要javac来编译jsp文件)。 用带命令行参数的java命令建立称为tomcat.home的系统环境,用org.apache.tomcat.startup.Tomcat作为启动类(startup class)。它也把命令行参数传递到org.apache.tomcat.startup.Tomcat,诸如: 执行开始/停止/运行等等(start/stop/run/etc)的操作。 被这个Tomcat进程(process)所用的 server.xml 文件的路径。 例如:如果server.xml位于/etc/server_1.xml,而用户想要在后台(background)中启动apache,他们应该使用下列的命令行: bin/tomcat.sh start -f /etc/server_1.xml Win32 设置包含下列信息的 CLASSPATH - 在 %TOMCAT_HOME%\lib 目录中的 servlet.jar, webserver.jar, jasper.jar, xml.jar %TOMCAT_HOME%\classes (即使不存在也会设置), %JAVA_HOME%\lib\tools.jar (其中包含执行jsp文件所需的工具javac). 执行java,假定它的路径在PATH中,用带命令行参数的java命令建立称为tomcat.home的系统环境,用org.apache.tomcat.startup.Tomcat作为启动类(startup class)。它也把命令行参数传递到org.apache.tomcat.startup.Tomcat,诸如: 执行开始/停止/运行等等(start/stop/run/etc)的操作。 被这个Tomcat进程(process)所用的 server.xml 文件的路径。 例如:如果server.xml位于 conf\server_1.xml,而用户想要在后台(background)中启动apache,他们应该使用下列的命令行: bin\tomcat.bar start -f conf\server_1.xml <

小小豆叮

Java平台最“体贴”的工具--javadoc

在软件项目管理过程中,如何保证程序代码与软件技术文档一致可以说是最令人头疼的一件事情了。不管是先修改代码,还是先修改文档,对各种记录的管理都是一件麻烦事。而且,二者在改动上的一致性、实时性还很难得到保证。令人高兴的是Java平台的设计者充分考虑到了这一点,他们十分"体贴"地为Java开发者们带来一个文档管理工具--javadoc。
javadoc利用Java编译程序javac对程序代码源文件中的声明和文档注释进行语法分析,并在默认情况下生成一组HTML文档来描述类、内部类、接口、构造函数、方法和域。不过在运行过程中,它也使用了Java平台的环境变量classpath来确定类查找路径。这样当涉及类和内部类的有关描述时,是否正确地设置了classpath变量可能会影响到javadoc命令是否可以完全成功执行。
javadoc产生的默认文件列表如下:

基本页面文件:
calssname.html 类或者接口描述文件,一个文件对应一个类或者接口
package-summary.html 包摘要文件,一个文件对应一个包
overview-summary.html 总的摘要文件

交叉引用页面文件:
overview-tree.html 所有包的类层次页面
package-tree.html 某个包的类层次页面
package-use.html 包用法页面
class-use\classname.html 类用法页面
deprecated-list.html 不鼓励使用的方法的页面
serialized-form.html 序列化页面
index-*.html 索引文件

支持文件:
help-doc.html 帮助文件
index.html 引导页面,是整个文档的入口
*-frame.html 框架文件
stylesheet.css 样式表文件
doc-files目录 保存与HTML相关的一些杂文件。例如图片文件等。
javadoc的命令行语法如下:
javadoc [ options ] [ packagenames ] [ sourcefiles ] [ @files ]
参数可以按照任意顺序排列。下面分别就这些参数和相关的一些内容进行说明:
  • Packagenames 包列表。这个选项可以是一系列的包名(用空格隔开),例如java.lang java.lang.reflect java.awt。不过,因为javadoc不递归作用于子包,不允许对包名使用通配符;所以你必须显示地列出希望建立文档的每一个包。
  • Sourcefiles 源文件列表。这个选项可以是一系列的源文件名(用空格隔开),可以使用通配符。javadoc允许四种源文件:类源代码文件、包描述文件、总体概述文件、其他杂文件。
    ◇ 类源代码文件:类或者接口的源代码文件。
    ◇ 包描述文件:每一个包都可以有自己的包描述文件。包描述文件的名称必须是"package.html",与包的.java文件放置在一起。包描述文件的内容通常是使用HTML标记写的文档。javadoc执行时将自动寻找包描述文件。如果找到,javadoc将首先对描述文件中<body></body>之间的内容进行处理,然后把处理结果放到该包的Package Summary页面中,最后把包描述文件的第一句(紧靠<body>)放到输出的Overview summary页面中,并在语句前面加上该包的包名。
    ◇ 总体概述文件:javadoc可以创建一个总体概述文件描述整个应用或者所有包。总体概述文件可以被任意命名,也可以放置到任意位置。-overview选项可以指示总体概述文件的路径和名称。总体概述文件的内容是使用HTML标记写的文档。javadoc在执行的时候,如果发现-overview选项,那么它将首先对文件中<body></body>之间的内容进行处理;然后把处理后的结果放到输出的Overview summary 页面的底部;最后把总体概述文件中的第一句放到输出的Overview summary页面的顶部。
    ◇ 其他杂文件:这些文件通常是指与javadoc输出的HTML文件相关的一些图片文件、Java源代码文件(.java)、Java程序(.class)、Java小程序(Applets)、HTML文件。这些文件必须放在doc-files目录中。每一个包都可以有自己的doc-files目录。举个例子,你希望在java.awt.Button的HTML文档中使用一幅按钮的图片(Button.gif)。首先,你必须把图片文件放到C:\user\src\java\awt\doc-files\中;然后在Button.java文件中加入下面注释
    /**
    * This button looks like this:
    * <img src="doc-files/Button.gif">
    */
  • @files 包含文件。为了简化javadoc命令,你可以把需要建立文档的文件名和包名放在一个或多个文本文件中。例如,为了简化下面命令:
    javadoc -d apidoc com.mypackage1 com.mypackage2 com.mypackage3
    你可以建立一个名称为mypackage.txt的文件,其内容如下:
    com.mypackage1
    com.mypackage2
    com.mypackage3
    然后执行下面命令即可:
    javadoc -d apidoc @mypackage.txt
  • options 命令行选项。javadoc使用doclets(doclets是指用doclet API编写的程序。)来确定输出的内容和格式。命令行选项中一部分是可用于所有doclet的通用选项,一部分是由默认的标准doclet提供的专用的选项。下面对各自一些常用的选项分别进行介绍:
    通用选项:
    -1.1 生成具有javadoc 1.1版本生成的文档的外观和功能的文档。不是所有的选项都可以用于-1.1选项,具体可以使用javadoc -1.1 -help察看。
    -help 显示联机帮助。
    -bootclasspath classpathlist 指定"根类"(通常是Java平台自带的一些类。例如java.awt.*等)的路径。
    -sourcepath sourcepathlist 指定包的源文件搜索路径。但是必须注意,只有在javadoc命令中指定了包名的时候才可以使用-sourcepath选项。如果指定了包名,而省略了-sourcepath,那么javadoc使用类路径查找源文件。举例说明:假定你打算为com.mypackage建立文档,其源文件的位置是C:\user\src。那么你可以使用下面的命令:
    javadoc -sourcepath c:\user\src com.mypackage
    -classpath classpathlist 指定javadoc查找"引用类"的路径。引用类是指带文档的类加上它们引用的任何类。javadoc将搜索指定路径的所有子目录。Classpathlist可以包含多个路径(使用;隔开)。如果省略-classpath,则javadoc使用-sourcepath查找源文件和类文件。举例说明:假定你打算为com.mypackage建立文档,其源文件的位置是C:\user\src,包依赖C:\user\lib中的库。那么你可以使用下面的命令:
    javadoc -classpath c:\user\lib -sourcepath c:\user\src com.mypackage
    -overview path\filename 告诉javadoc从path\filename所指定的文件中获取概述文档,并且把它放到输出的概述页面(overview-summary.html)中。其中path\filename是相对于-sourcepath的相对路径。
    -public 只显示公共类以及成员。
    -protected 只显示受保护的和公共的类以及成员。缺省选项。
    -package只显示包、受保护的和公共的类以及成员。
    -private 显示所有类和成员。
    -doclet class 指定javadoc产生输出内容的自定义doclet类。如果忽略这个选项,javadoc将使用默认的doclet产生一系列HTML文档。
    -docletpath classpathlist 与- doclet选项相关,制定自定义的doclet类文件的路径。Classpathlist可以包含多条路径(用;隔开)。
    -verbose 在javadoc运行时提供更详细的信息。
    标准doclet专用选项:
    -author 在生成的文档中包含"作者"项。
    - d directory 指定javadoc保存生成的HTML文件的目录。省略该选项将把文件保存在当前目录。Directory可以是绝对目录,也可以是相对当前目录的相对目录。
    -version 在生成的文档中包含"版本"项。
    -use 为类和包生成"use"(用法)页面。这些页面描述了该类和包在javadoc命令涉及的文件中被使用的情况。例如:对于给定的类C,在C的用法页面中将包含C的子类,类型为C的域,返回变量类型为C的方法以及在参数中有变量类型为C的方法和构造器。
    -splitindex 把索引文件按照字母顺序分为多个文件。每一个文件对应一个字母。
    -windowtitle title 指定输出的HTML文档的标题。
    -header header 指定输出的HTML文档的页眉文本。
    -footer footer 指定输出的HTML文档的脚注文本。
    -bottom text 指定输出的HTML文档底部的文本。
    - group groupheading packagepatten;packagepatten;… 在总体概述页面中按照命令的指定方式分隔各个包。例如执行下面命令:
    javadoc -group "Core Packages" "java.lang*:java.util"
    -group "Extension Packages" "javax.*"
    java.lang java.lang.reflect java.util javax.servlet java.new
    在页面中将有如下结果:
    Core Packages
    java.lang
    java.lang.reflect
    java.util
    Extension Packages
    javax.servlet
    Other Packages
    java.new
    ◇ - noindex 不输出索引文件。
    ◇ - help 在文件的导航条中忽略help链接。
    ◇ - helpfile path\filename 指定导航条中的help链接所指向的帮助文件。忽略该选项,javadoc将生成缺省的帮助文件。
    ◇ -stylesheetfile path\filename 指定javadoc的HTML样式表文件的路径。忽略该选项,javadoc将自动产生一个样式表文件stylesheet.css。
    通过上面的介绍,我们了解了javadoc的命令行语法,下面开始介绍javadoc文档注释方法。
    javadoc注释以"/**"开始,以"*/"结束,里面可以包含普通文本、HTML标记和javadoc标记。javadoc只处理源文件中在类/接口定义、方法、域、构造器之前的注释,忽略位于其他地方的注释。举例如下:
    /**
    *我的第一个程序--<b>Helloworld</b>
    *@author 王鸿
    *@version 1.0 2001/10/15
    */
    public class myHelloworld
    {
    /**
    *在main( )方法中使用的显示用字符串
    *@see #main(java.lang.String[])
    */
    static String SDisp 使用下面命令:
    javadoc -private -d doc -author -version myHelloworld.java
    即可以生成漂亮的关于myHelloworld.java的API文档了。
    上面例子中以@开头的标记就是javadoc标记。在Java程序中正确使用javadoc标记是一个良好的注释习惯,将非常有助于javadoc自动从源代码文件生成完整的格式化API文档。下面就对各种标记进行详细说明。
    @author name-text 指定生成文档中的"作者"项,从JDK/SDK 1.0开始引入。name-text可以指定多个名字(使用","隔开)。文档注释可以包含多个类。
    {@docroot} 代表产生文档的根路径,从JDK/SDK 1.3开始引入。用法举例如下
    /**
    *see the <a href={@docroot}/copyright.html>copyright</a>
    */
    假定生成文档的根目录是doc,上面注释所在的文件最后生成的文件是doc\utility\utl.html,那么"copyright"的链接会指向..\copyright.html。
    @deprecated deprecated-text 添加注释,表明不推荐使用该API。
    @exception class-name description @throw的同义标记,从JDK/SDK 1.0开始引入。
    {@link package.class#member label} 插入指向package.class#member的内嵌链接,从JDK/SDK 1.2开始引入。举例说明,假定注释中有如下文档:
    /** Use the {@link #getComponentAt(int, int) getComponentAt} method. */
    那么javadoc最终生成的HTML页面中将有如下内容
    Use the <a href = "Component.html#getComponentAt(int,int)" > getComponentAt </a> method.
    @param parameter-name description 描述参数,从JDK/SDK 1.0开始引入。
    @return description 描述返回值,从JDK/SDK 1.0开始引入。
    @see reference 添加"参见"标题,其中有指向reference的链接或者文本项,从JDK/SDK 1.0开始引入。@see标记有三种形式,下面分别说明:
    (1)、@see "string" 为"string"添加文本项,不产生链接。
    (2)、@see <a href="URL#Value">Label</a> 使用HTML标记产生链接
    (3)、@see package.class#member Label 使用Java语言的名字package.class #member产生链接。
    ◇ @serial field-description 用于缺省可序列化域的注释,从JDK/SDK 1.2开始引入。
    ◇ @serialField field-name field-type field-description 建立Serializable类的serialPersistentFields成员的ObjectStreamField组件的文档,从JDK/SDK 1.2开始引入。
    @serialData data-description data-description建立数据序列和类型的文档,从JDK/SDK 1.2开始引入。
    @since since-text 利用since-text内容为文档增加"since"标题,从JDK/SDK 1.1开始引入。
    @throws class-name description 与@exception同义。用class-name和description为输出文档添加"抛出"标题,从JDK/SDK 1.2开始引入。
    @version version-text 添加"版权"标题,从JDK/SDK 1.0开始引入。
    上面介绍了标准doclet提供的所有标记。不过,需要注意这些标记的使用是有位置限制的。其中可以出现在类或者接口文档注释中的标记有:@see、{@link}、@since、@deprecated、@author、@version。可以出现在方法或者构造器文档注释中的标记有:@see、{@link}、@since、@deprecated、@param、@return、@throws、@exception、@serialData。可以出现在域文档注释中的有:@see、{@link}、@since、@desprecated、@serial、@serialField。
    除了javadoc自身提供的标准标记以外,我们可以定制自己的标记吗?当然可以。只需要对javadoc标准的doclet程序进行扩充即可。实际上,利用javadoc提供的doclet API,不仅可以扩充doclet标记,甚至还可以改变javadoc的整个输出。为了满足需要,你可以使javadoc输出普通文本、XML文件等。由于扩充doclet涉及到Java编程,本文不再做深入介绍。
    总之,javadoc提供了完整规范的API文档功能。在软件项目管理中,合理地使用javadoc不仅可以减少开发时的文档工作量,提高效率;而且还非常有利于将来软件的修改和维护。
    <

小小豆叮

利用Socket进行Java网络编程

 Socket是网络上运行的两个程序间双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以较为方便的编写网络上数据的传递。在Java中,有专门的Socket类来处理用户的请求和响应。利用Socket类的方法,就可以实现两台计算机之间的通讯。这里就介绍一下在Java中如何利用Socket进行网络编程。   在Java中Socket可以理解为客户端或者服务器端的一个特殊的对象,这个对象有两个关键的方法,一个是getInputStream方法,另一个是getOutputStream方法。getInputStream方法可以得到一个输入流,客户端的Socket对象上的getInputStream方法得到的输入流其实就是从服务器端发回的数据流。GetOutputStream方法得到一个输出流,客户端Socket对象上的getOutputStream方法返回的输出流就是将要发送到服务器端的数据流,(其实是一个缓冲区,暂时存储将要发送过去的数据)。   程序可以对这些数据流根据需要进行进一步的封装。本文的例子就对这些数据流进行了一定的封装(关于封装可以参考Java中流的实现部分)。   为了更好的说明问题,这里举了一个网上对话的例子,客户端启动以后,服务器会启动一个线程来与客户进行文字交流。   要完成这个工作,需要完成三个部分的工作,以下依次说明:   一、建立服务器类   Java中有一个专门用来建立Socket服务器的类,名叫ServerSocket,可以用服务器需要使用的端口号作为参数来创建服务器对象。 ServerSocket server = new ServerSocket(9998)   这条语句创建了一个服务器对象,这个服务器使用9998号端口。当一个客户端程序建立一个Socket连接,所连接的端口号为9998时,服务器对象server便响应这个连接,并且server.accept()方法会创建一个Socket对象。服务器端便可以利用这个Socket对象与客户进行通讯。 Socket incoming = server.accept()   进而得到输入流和输出流,并进行封装 BufferedReader in = new BufferedReader(new       InputStreamReader(incoming.getInputStream())); PrintWriter out = new PrintWriter(incoming.getOutputStream(),true);   随后,就可以使用in.readLine()方法得到客户端的输入,也可以使用out.println()方法向客户端发送数据。从而可以根据程序的需要对客户端的不同请求进行回应。   在所有通讯结束以后应该关闭这两个数据流,关闭的顺序是先关闭输出流,再关闭输入流,即使用 out.close(); in.close(); <

小小豆叮

开发完整J2EE解决方案的八个步骤 4

应用体系   应用体系建立在企业系统体系之上,指的是一个特别的项目或者应用。在架构完成后,体系建立人员就会研究如何建立一个专门的应用。如果你的企业体系只是支持一个旧的J2EE版本,你可能就需要首先升级你的系统。如果由于预算或者时间关系而不能做升级,那么就必须在旧版本的技术限制下工作。重要的是,要建立企业级的可重用组件。最终的目标是要满足客户的需要。   一个体系建立者并不是一个设计者;体系和设计是两件不同的事情。一个应用体系的范围是系统的主要结构、它的体系设计模式以及你可以在上面增加组件的架构。体系主要是涉及实现的非功能性方面,而设计是和商业的use cases有关,use cases是指你应用来转换域对象模型为一个技术对象模型的部分。应用体系是项目的结构,一个专门的应用。你通常在应用体系结构开发时要作出的决定包括有:   。层间的功能划分   。模型域对象   。以前的系统需要保存的东西   。购买的软件组件   。需要建立的组件   。如何集成第三方的组件   图3中的订单域对象解释了你如何做到模型化域对象。对于当前的Java技术,你可以将域对象分布在几个地方,包括有作为开发者管理的持续对象放在Web容器中,作为EJB放在应用服务器中,或者作为存储过程放在RDBMS主机中。   在宠物店的设计图中,我们将订单对象设计为一个实体bean、一个细节的对象和一个数据访问对象,如图5和后面的图6所示。当你看到这些时,你将会认识到其体系的重要性。你可以想一下为什么一个在分析模型的域对象被映射为这么多对象,以及如果改变该设计的话,将会发生什么事情。你也许已经听到过EJB的好处,不过要注意的是不同厂家实现起来的性能是有区别的。当新技术到来时,在将其放在到一个系统之前,你需要做研究并且动手做一些测试。其实所谓体系的开发,就是将设计和实现域对象模型的垂直块转换为设计其它许多域对象。 *****************图5*********************   在J2EE出现的早期,一些面向对象的设计者尝试将域对象映射到实体bean中,并且将它们在层间传送。他们拥有非常好的UML框图,不过得到的结果是一个慢的系统,这是由于不必要的网络通信造成的。由对象分析直接进入对象设计,而没有一个体系的设计,没有清楚地理解一个新技术,这样通常都会导致一个项目失败。   可交付的体系   由于J2EE体系是一个相对新的主题,因此一个可交付的J2EE体系并没有很好地定义。在宠物店的例子应用中,是很难看出体系在哪里结束和设计在哪里开始。文档由高级别的应用体系检查、Model-View-Controller设计模式的讨论和一个体系概览开始。低级别的文档就是源代码。没有UML框图。Sun的J2EE企业体系认证的委派部分要求所有的可交付体系都用UML表示。不过,这里仅表示为一个类框图、一个组件框图和一些对象交互框图,。这些对于一个真正的J2EE应用来说都是不足够的。要开始的话,体系规范和流程至少需要以下的方面:   .一份系统体系文档,用来描述你现有的硬件、软件、网络拓扑和其它的组件   .一个应用体系文档,用来描述应用的主要结构,包括所有对于体系有重要作用的组件、use case组件和以前的组件的一个逻辑视图   .一个新组件设计指导方针,用来描述所有的设计方针和体系决定,解释全部这些决定,并且说明如果选择其它的选项会有什么可能的结果。这些方针应该包含所有重要的基本决定,以便进行新组件的设计时可遵从这些规定,以维持系统体系的完整性   。一个工作体系原型来评估新的技术;从开发和配置J2EE应用中获取经验;建立体系架构;通过测量性能、扩展性来预示所冒的风险;还有向客户证明你的方法是可行的   在你开发过几个J2EE方案并且获得更多的经验后,原型将不再那么重要,这时一些UML框图和一些设计方针就可能已经足够了。 <

小小豆叮

开发完整J2EE解决方案的八个步骤 3

  III、体系规范   经过前面的两个步骤,商业领域的问题和需求都应该清晰了。现在我们将集中讨论技术策略和体系上。一个体系就是各部分一起定义整个系统的蓝图:结构,接口和通信技术。我们可进一步将一个体系划分为企业和应用体系。   企业系统体系   企业系统体系覆盖了硬件和软件架构,网络拓扑,开发、测试和生产环境等。这些都反映了一个企业的长线投资。在开发前,你需要评估现有的软件和硬件架构,如果它不能完全支持J2EE的话,你可能会加入新的组件和升级你现有的系统。你需要彻底地评估硬件,包括有计算机,路由器、交换机和网络拓扑,因为它们都会影响系统的性能和稳定,图4展示了一个多层的网络拓扑。 **************图四***************   图4中的多层企业体系拥有以下主要的组件:    .Web浏览器客户端,它可能处在客户端公司的防火墙后面    .HTTP服务器,它通常处在DMZ区    .Web容器主机提供表现或者商业逻辑组件    .应用容器提供商业逻辑组件    .关系数据库管理系统(RDBMS)和数据库提供数据和数据逻辑   所使用的系统体系类型是根据你对安全、性能、可靠性的需求以及你公司的财政状况而定的。要求很低时,你甚至可以使用一台二手的计算机和一条电话线。在Internet上,有许多开放源代码的操作系统、Web服务器、应用服务器和数据库管理系统。这些系统的花费可能只有几百美金,当然,维护起来可能要麻烦一点。   高端的客户,例如许多华尔街的财政机构,它们需要的是一个支持安全、高吞吐量和可应付不可预计网络通信的系统。在这种情况下,你通常就需要一个n层的体系,该体系带有Web服务器和应用服务器,并且设置为群集而达到容错的目的。   你还需要评估软件架构,包括Web服务器,安全管理软件,应用服务器,域名管理服务器,数据库管理系统和第三方的软件组件,如果你还没有购买你的应用服务器,那么在评估过程中,选择一个J2EE的生产商将是一个重要的部分。我要提醒你一点,不同厂家对J2EE的实现是有很大不同的,有一些仅支持旧的J2EE版本。此外,一些Web容器或者应用容器可能要比其它的快不少。除了实现J2EE规范外,许多的厂家还售卖J2EE体系的组件或者架构。选择一个稳定的J2EE厂家也是重要的,因为这样可以得到长久的支持。你通常可以购买或者在系统体系级别开发的功能包括有:   。事务处理   。国际化和本地化   。群集和对象分布   。Session管理   。应用性能测量和描述   。消息   。工作流管理   。入口和个性化管理   。层到层通信协议   。安全和防火墙 <

小小豆叮

开发完整J2EE解决方案的八个步骤 1

摘要   Java 2企业版本(The Java 2 Enterprise Edition,J2EE)平台由4个主要的部分组成:规范,参考实现,兼容性测试包和BluePrints程序。BluePrints描述了一个分布式组件体系的最佳练习和设计指导方针。这篇文章介绍了一个由八个步骤组成的J2EE开发方法论,该方法是基于Rational Unified Process和BluePrints应用例子的。通过这篇文章,你将可以更好地理解J2EE体系的许多重要主题,并且可以应用这些知识来扩展和修改这个简单的方法论,从而解决各种特定的商业问题。   在商业领域,我们使用Java 2企业版本(J2EE)来解决商业问题,开发商业的软件,或者为其它的商业项目提供联系的服务。如果一个公司要使用多层的体系来建立一个电子商务的网站,在其整个开发周期中,通常都需要经理、体系构建人员、设计人员、编程人员、测试人员和数据库专家参与进来。   为了让不同的部分可以有效地工作,我们通常都需要一个软件开发流程。一个经典的开发流程包括有瀑布模型、快速应用开发(RAD)和最终编程。在这篇文章中,我们将集中介绍一个流行的软件设计流程--Rational Unified Process(RUP)。RUP提供了一个专门的方法来为不同的角色分配任务。它的目标是在一个可预计进度和预算内,确保我们生产出高质量的软件以符合用户的需要。   我使用RUP作J2EE开发有三个方面的原因。首先,RUP是以体系为中心的;在提交资源作全方位的开发之前,它首先开发出一个可执行的体系原型。第二,RUP是迭代的而且是基于组件的。该体系的基本通常是包含有一个架构,它可以方便地通过迭代地增加组件,从而在不影响系统其它部分的基础上,自定义和扩展一个系统的功能。第三。RUP使用一个工业标准的语言--UML,可以将系统的体系和组件以可视化的模型展示。RUP有4个不同的开发阶段:初始(inception), 细化(elaboration), 构建(construction)和转换(transition)。这篇文章将从一个技术的观点来介绍J2EE开发的8个基本步骤,它是维持以体系为中心的。   1、需求分析   需求分析用来描述系统应该和不应该做什么,从而开发者和用户可以创建一个初始化的商业联系。你可以用商业的概念、该领域的术语、框图或者其它方法将功能性的需求写成文档,而非功能性的需求,例如性能和事务,可以写在附加的需求文档中。你可以用文本或者HTML来创建高级别的UI模型,采取哪种方式,要看你在该项目中介入的深度。   图一展示了一个典型的电子商务系统。viewOrder图说明的是一个用户通过web登录至系统,查看订单的列表,并且可点击进去查看每张订单的细节。addLineItems说明的是用户浏览产品目录,选择感兴趣的产品,并且将它们加入到购买订单中。 ******************图一************ <

小小豆叮

jakarta-tomcat.zip[2.26MB]

<

小小豆叮

图文:摩托罗拉推出两款Java手机

摩托罗拉公司星期一推出了i90c和i80s两种新型手机。这两种造型优美的手机允许用户下载应用程序对手机进行自定义设置。   摩托罗拉i90c型手机是袖珍可折叠式手机,i80s型手机具有细长的雕塑风格。这两种手机都有一套丰富的功能,包括使用应用程序升级以满足用户变化的需求。这两种手机还有移动办公室、游戏机、计算器等功能。   摩托罗拉i90c和i80s型手机使用了Java技术使用户能够下载和运行应用程序,使手机能够执行多种任务。这两种手机都提供免提电话听筒,以便用于临时的电话会议、语音拨号和录音机。双向无线电功能允许用户按下一个按键就能同一个人或数百个人即时通话。其它功能还包括可存储250条信息的电话号码本、日历和自定义风格设置,该功能可使用户适应不同的用户环境,如办公室、汽车和家里。   摩托罗拉i90c型手机为深蓝色,有蓝色背光双显示屏和小键盘。该手机有外部显示功能,用户不用打开手机就能看到打电话者的身份、日期和时间。该手机的智能按键可使用户不打开电话只按下一个按键就能执行多重任务。10种可选择的音乐文件和10种可选择的铃声可使用户对铃声进行个性化设置。铃声包括模仿16种乐器的丰富的复调音乐声音。该手机预装了若干应用程序,包括计算器、记事本和一款名为“Borkov”的世嘉游戏。 摩托罗拉i90c型手机的尺寸为90毫米 x 50毫米 x 28毫米,重量114克。   摩托罗拉i80s型手机的颜色为流行的银色,是一种线条明快的超薄型手机。该产品预装了数学计算器和尖端计算器。该产品是第一个支持一种新的免提耳机和麦克风附件的手机。这种附件有一个按下即通话的按钮,使用户能够使用耳机进入数字双向无线电通信。   摩托罗拉i80s型手机的尺寸为138毫米 x 49毫米 x 25毫米,重量123克。 <

小小豆叮

开发完整J2EE解决方案的八个步骤 5

IV、对象设计   在体系规范的指导下,设计可在技术上扩展和适应分析的结果。分析阶段时,域对象模型化应该和技术的细节无关,而对象设计时则是和技术因素密切相关的,包括在体系开发阶段时,采用哪一类的平台、语言和厂家。理论上,你不要修改商业对象,除非是为了维护它们基本的属性和行为而必须这样做。   在体系决议的指导下,一个详细的设计说明应该提到所有类的规范,包括必要的实现属性,它们详细的接口和伪代码或者操作的纯文本描述。规范的详细程度应该达到只要和模型框图结合,就可得到所有必要的编程信息。在许多自动化的软件生产流程中,你可以从面向对象的框图中产生代码的框架。要注意的是stub和skeleton通常是无需在框图中展示出来的,因为它们对于设计者和编程者来说都是透明的。我在图6中包含它们只是为了说明EJB的基本点。 ****************图六**************   在你完成详细的对象设计后,你就完成了域对象的对象相关映射。这样做的原因是,虽然面向对象的方法论在目前是比较先进的,不过最流行和持久的商店都是关系型的。此外,一个客户的IT架构在许多方面都已经反映了现有的投资和商业RDBMS厂家的选择。因此将域对象模型转换为关系模型或者数据库表是非常重要的。有很多容器管理的工具,不过它们不能代替一个好的关系数据库设计。   V、实现   有了一个好的架构和细节设计,实现将是一个很清晰的任务。此外,由于我们在体系原型阶段设计和实现了系统的一个垂直部分,因此在实现阶段我们不会碰到很多麻烦事情。在许多公司中,开发者通常都是过早进入实现阶段,特别是当经理在监视他们的时候,因为对于他们,做其它的事情等于浪费公司的时间。   结果是,不再花时间来画UML框图,而是在代码开发中测试想法,这要花数星期和几个月的时间,在这种情形下,所有的体系决议和设计都是在代码阶段作出的,通常要在几个月后才会发现开发已经进入了一个错误的方向。   VI、确认   确认包括有测试以验证该系统符合设计并且满足需求。在整个开发周期中,验证发生在开发和安装阶段。单元测试、集成测试和用户容忍度测试都是重要的主题 <

小小豆叮

JSP使用环境的配置

JSP(Java Server Pages)基于Java技术,并在传统的网页HTML文件( <

小小豆叮

开发完整J2EE解决方案的八个步骤 6

  VII、组合和配置   组件装配和方案配置在J2EE的开发中是特别重要的。开发和安装的环境可能是完全不同的。如果EJB处在系统中,你需要使用厂家的专门工具来提出产生容器的类,上面我也提到过,Web或者应用组件的配置对于不同的厂家都是不一样的。你还必须考虑要配置的系统是否拥有任何厂家指定的代码实现。在一个可扩展的体系中,系统的结构应该是稳定的,但是应该可以支持增加配置新的或者旧的组件,而无需影响整个系统。   VIII、运作和维护   在最后的阶段,应用交付到用户的手中,你必须为他们提供培训、文档和教育。用户将会发现问题和可能会提出新的改进。你必须通过正确地修改管理过程来处理这些需求。你无需为了配置一个新的组件或者替换一个旧的组件而关闭一个正在工作的系统。   体系开发流程   我们必须做许多体系的决定,因此我们必须整理出一个体系开发的流程。对于一个企业来说,通常有许多应用项目,其中的一些甚至会跨越几年,从而导致系统围绕许多周期而变化。在你的领域中,许多同样的项目中都会出现同样的需求。你应该很容易地重新使用一个扩展的和可重用的体系,它们可能在上个项目周期或者其它的项目中。这样会有一个对普遍架构的需求,可重用的软件架构可为家族式的软件应用提供一个普遍的架构。   如果这是你的首个J2EE项目,你的体系必须被原型化,进行测试、分析,然后再重复。BluePrint提供了许多好的设计指导方针和最佳的练习,宠物店的例子也是一个很好的参考体系。要很快地提出一个好的并且是高质量的解决方案的有效方法是使用和扩展BluePrint参考体系,然后插入到你自己的商业组件中。   使用参考体系   就我的理解来说,宠物店体系的本质是Model-View-Controller和Command模型。你可以将这些模型应用到以Web-centric和EJB-centric的系统。对于每个域对象,一个视图是用嵌套的JSP表现。一个controller处理与商业相关的事件,而域对象封装商业逻辑、事务和安全。我们使用前台的servlet作为中央的controller,以接收和解释所有用户的操作。它分派商业事件到指定的域对象controllers,这些controllers可调用域对象来改变持续的状态。根据这个事件处理的结果,一个controller选择下一个显示的视图。以下的组件对于体系都是很重要的,我们可以修改并且应用在大部分的J2EE应用:   MainServlet: 前台的组件是Web容器和该架构之间的接口   ModelUpdateListener: 是获取模型更新事件的对象的接口   ModelUpdateNotifier:在更新模型事件发生的时候通知监听者   RequestProcessor: 处理由MainServlet接收的全部请求   RequestHandler:plug-n-play请求处理器组件的接口   RequestHandlerMapping:包含有请求处理器映射规则   RequestToEventTranslator:根据请求处理器的映射规则,中央请求处理器委派请求处理到plug-n-play请求处理组件。到商业事件的透明http请求   EStoreEvent: 商业事件   ShoppingClientControllerWebImpl: Proxy-to-EJB层前台控制器   ScreenflowManager: 控制屏幕流,选择视图   ModelUpdateManager: EJB层模型更新管理器,通报由于一个事件而导致的模型修改   ShoppingClientControllerEJB: EJB层前台,为EJB客户提供远程服务   StateMachine:中央事件处理器,根据状态处理器的映射规则,委派事件处理至plug-n-play处理器组件   StateHandler: EJB层状态处理器接口   StateHandlerMapping: 包含状态处理器映射规则   扩展参考体系   BluePrint的例子应用是一个好的起点,你还应该修改它以配合不同的项目和领域。设计模型是可重用的微体系,你可以使用它来扩展参考体系。BluePrint提供了一个非常有用的J2EE模型目录,而23个“Gang of Four”模型都是极好的资源。例如,如果你想扩展参考体系以支持工作流管理,你可以在配置或者运行时使用中央controller来动态注册事件处理器。中央controller要求每个注册的事件处理器处理一个事件,直到一个处理器返回一个指示已经到达命令串末尾的信息。   插入你的商业组件   J2EE技术对于每个人都是一样的,但是对于不同的领域,我们需要解决的问题都是不同的。一旦你建立了一个基本的J2EE框架,你就必须利用一些use cases来展示该体系可为你的领域工作。你可以通过选择一些情形,最好是该系统的一个重要的功能,或者使用得最多的而且可带来明显的技术上的冒险的情形。由域分析模型开始,然后尝试映射你的域对象到高端和低端的设计模型,就象我们在图5和6中的所示。实现低级别的设计模型,并且测试看它是否真正地运作。如果所有都如设想般运作,你就可以再重复上一步,即找冒险的情形、更多的设想来测试以扩展体系的覆盖。在经过反复的验证后,初始化的体系原型应该就会变得稳定。你可以认识到哪些组件是可以购买的,旧系统的哪些方面是应该保留的,以及如何为它们做接口。下一步就是软件设计,你可以使用设计指南中指定的类似方法和流程来进行继续的开发。   按部就班   我们使用了一个流程的形式,将一个复杂的问题分解为几个小的部分,以便我们能更容易地理解和解决它们。在这篇文章中,我们将J2EE的开发分解为8个步骤,集中介绍了体系和设计。我这里介绍了重要的体系主题和作出体系决定的一个流程。我还讨论了J2EE体系的角色和可交付。   学习通过这些步骤来开发J2EE的方案就象学习舞蹈一样。你首先需要自觉和坚持不懈地练习基本的舞步。一旦你熟悉了它们,你就会想到将它们放在一起,并且更集中在曲子里每步的大小、速度、流和节奏。不过你不应该被一个流程来限制你的创造力。相反,你应该使用和扩展该流程来满足你的特定需要。要记住,你的最终目标是设计出一个完整的J2EE方案来满足你的客户需求。 <

小小豆叮

开发完整J2EE解决方案的八个步骤 2

  II、面向对象的分析   分析产生问题域模型:类、对象和交互。你的分析应该脱离任何的技术或者实现的细节,而应该包含有一个理想的模型。对象分析可帮助你理解问题和获得问题领域方面的知识。你必须维护一个纯领域的模型,它不包含技术的细节,这是由于商业流程的改变要比信息技术慢得多。   上面的两步--需求分析和面向对象的分析并不是J2EE特有的,对于许多面向对象的方法论来说,都是很常见的。图2展示了一个高级别的对象分析模型,它是一个宠物店的例子应用。它说明了我们由需求分析use cases中确定的主要概念。我们将这些概念模型化到对象中,并且确定它们的关系。   需求和对象分析的结果是J2EE体系开发的一个入门点。要开发一个体系,你可选择一个垂直的部分--通常是一个关键的部分,例如是订单领域的对象模型--来作对象设计、实现、测试和开发。(一个垂直的部分,是一个RUP概念,是系统的一小部分。开始点是use case的一个子集,如图1所示,还有领域分析模型,如图三所示。一个垂直部分的实现就会产生一个全功能的迷你系统,包括所有层,例如用户界面层的JavaServer Pages(JSPs),中层的商业对象,例如是Enterprise JavaBeans (EJBs)和后台的数据库)。你可以将由原型中得到的经验应用到域对象中,并且将这些认识作为对象设计阶段的一个设计指导方针。 **************图三***************** <

小小豆叮

全面保护你的Java程序(中)

第二部分:不要让漏洞危及应用程序安全 概论:在这个部分的安全讨论中,Todd Sundsted和我们一起讨论应用程序安全问题。在程序开发中的微小错误都可能给开发人员和用户带来很大的安全问题。Todd在这里将展示如何设计及实现这种最普通的安全漏洞类型,并描述了如何避免这些问题。他还提供了一个来自Sun自己JDK中的一个漏洞示列。 大多数软件开发人员都能意识到那些恶意或是仅仅是好奇的黑客所带来的威胁,但很少开发者认识到他们无意中带到程序中的漏洞造成的影响范围有多大。这些带到程序中的漏洞无疑纵容,帮助了所谓的黑客们。 在今年一月,一名德国的软件开发人员证实在最近开发源代码产品Borland的数据库 InterBase中有个带有严重安全隐患的设计上的漏洞。在这个InterBase版本中的漏洞甚至可以追溯回到1994年! 这个存在于登录名和密码验证窗体上的后门并非有人故意为之。然而,正是InterBase开发人员不当的设计造成了这个问题。这个程序使用了命名和密码验证来控制InterBase接入数据库。 尽管这个错误展现的是个极端的列子,但它所揭示的教训是很重要的:作为开发者,对于我们应用程序整体安全,我们的设计以及代码实现是非常关键的。并且,如上面的列子所示,由开发者带入程序中的漏洞可能会影响用户达数年时间。 ·回顾 上次,我们讨论了我们必须检查三方面的安全问题。这些问题尽管互不相同,但经常要求跨越三方面进行全面的考虑。Java程序的开发者必须要明白从这三方面来考虑他们解决方案的安全性问题对其产品的重要意义。 Java和非Java的开发者对这样一个最知名的安全问题都是熟悉的,那就是虚拟机安全。这源于对于JVM和运行时环境多年来大量的关注。虚拟机安全包含JVM和提供支持的运行时环境。在过去的几年里,虚拟机安全问题得到了加强,并得到了很好的重视。 最近,由于在JVM领域明显的漏洞已少,多数编程者的注意力已经从Java虚拟机安全转向到运行于其上的应用程序安全。而这些多数Java程序员在这层面将明显的影响到Java安全。在这方面,需要处理的是设计决定以及在开发中可能出现的意外问题。当然,不是所有这样的漏洞都会危及应用程序安全。我们将集中精力于那些能够危害程序的漏洞。 最后一方面的问题,网络安全问题,其基于网络的程序和程序组件之间的通信问题是安全问题方面的一个粮亮点。再次声明,不是所有这里介绍的漏洞都会危及安全,我们只注意那些能够危及安全的方面。 上次我们讨论了虚拟机安全问题并示范了VM安全方面的漏洞如何出现及进行破坏的。现在,我将讨论应用程序安全。这里,我举出一个最普通的有漏洞的类,以助你避免这样的问题。我会包含最近在Sun自己的代码中发现的列子。 很容易列出一个各种错误设计以及实现的列表清单,这里要说的列子只是其中的一个。但我将定义和描述出大多数Java程序安全弱点的一个分类目录。这个目录主要分为两大块:“实现相关”和“设计相关”的漏洞。 ·实现相关的漏洞: 实现相关的漏洞通常是在实现代码时带入到程序中的。这通常是由于粗枝大叶的代码编写,对需求理解不够充分,以及不熟练的编程技能等造成。实现相关的漏洞由于不充足的测试以及复核而常常隐藏的比较深。然而,如果系统设计良好,你就可以不改变设计而更正这些漏洞: ·定时问题: 最有害的定时问题是资源竞争问题。这样的问题在当两个没有经过适当同步的线程同时争夺同一个资源时发生。在这两个互相影响的线程或者是在不懈调,无效的状态下放弃对象,或者是当恶意代码利用了正被另一个线程使用又没有被很好的保护的资源时,安全漏洞就会出现。通常的解决办法是简单的加上同步措施。 ·不充分的输入校验: 系统的输入在使用前一定要经过检验。尽管某些输入是来自信任源,但出于安全考虑,所有这些输入都应该看作不被信任的,危险源。未经完全检查的输入可能带来大量严重的安全弱点。 ·不当的随机数: 好的加密系统需要高质量的随机数发生器。早前Netscape Navigator的大量安全漏洞直接就是来自于不适当的随机数发生器。随机数发生器产生的有效密匙达不到建议的长度,结果很容易遭到破解。 ·设计缺陷: 源自于实现部分的安全问题已经很糟糕,但最坏的情况是由于设计上的缺乏长远考虑,对语言及函数库的理解不够充分而引起的。这种漏洞通常使程序逻辑纠缠不清,必须花掉大量时间和耐心去处它,即便这样也会是很困难的事。上面提到的InterBase漏洞就是极好的这样的列子。 ·初始化问题: 大家都知道“new”操作并不是创建新实列的唯一方法。像克隆这样的方法也可以创建新的实列。你可以通过非常规的方法创建实列,以搞乱类的安全系统。 ·可见性和扩展性问题: 可见性(类或是其成员是否是公共的或是私有的),扩展性(子类是否能继承一个类或是方法)为软件开发人员提供了非常重要的工具。然而,如果使用不当,这也会造成一些微妙的漏洞。 在子类化的列子中,一个子类可以改变继承自超类的约定,定义。扩展后的代码使用一些自己的约定可以破坏程序安全。解决办法就是:合理使用“final”关键字,防止子类进行重定义。 同样,你可以通过使用关键字“private”防止类内部流程和状态被修改,反之,则可能将类内部细节暴露在随后添加到包中的类下。 ·绝不要放置“后门”: InterBase的设计就给我们提供了这样一个列子。你不能私自在程序里面建立什么后门代码。这些代码通常是位于密码校验和加密数据的窗体。这对于一个固执的黑客来说根本够不成障碍。一旦后门被破解,“潘多拉的魔盒”就打开了。 ·Sun自己也会犯错: 我非常尊敬Sun的工程师。然而,尽管他们都是很有天赋的人,但还是如你我一样会犯错误。 在2月23号,Sun宣布它发现了JDK中的一处漏洞。下面是他们的声明: “在某些Java运行时版本中的漏洞可能会允许恶意Java代码执行未经授权的命令。然而,恶意命令代码一定已经取得了代码执行的授权。” 如果这种代码在某种环境下被给予执行至少一条可执行命令(如echo),这个漏洞会允许不被信任的Java代码激活任何可执行命令(如格式化FORMAT)。这样的错误很可能隐藏很久而不被发现。 下面就让我们来看看具体的代码:这个漏洞是位于java.lang.Runtime类里的exec()方法中: public Process exec(String [] arstringCommand, String [] arstringEnvironment) throws IOException { // Ensure that the array parameters aren't null, their elements // aren't null, etc.   . . . // Do some stuff. . . . // Get the security manager. SecurityManager securitymanager = System.getSecurityManager(); // Check the first element of the command array -- which should // be the name of the executable to invoke. Ensure that it has // executable privilege. if (securitymanager != null) securitymanager.checkExec(arstringCommand[0]); // Now, invoke the executable. return execInternal(arstringCommand, arstringEnvironment); } 你看出问题了吗? 这个错误位于最后三行中(注释和空格除外)。首先,安全管理器检查可执行名,看其是否在配置文件中有执行的授权。接下来,代码执行命令。哎哟!在一个多线程环境中,参数数组内容在这两步之间就可以改变。由于这两个输入参数数组被直接使用,调用者仍然掌握着它们的引用,并且可以修改其内容。 更正:立即复制输入数组并在拷贝中进行操作。 ·回到最好的练习: 经由老式的软件开发练习,你可以发现很多导致安全问题的漏洞。清楚的需求,严格的设计核查,完整的代码核查,并通过详尽的测试可以挖出很多漏洞并进一步提高软件整体质量。 <

小小豆叮

全面保护你的Java程序安全(下)

第三部分:创建更安全的网络程序 概论:创建一个安全的网络程序,你需要考虑很多技术以外的东西。一个安全的解决方案除了前面讲到的虚拟机安全,应用程序安全外,还依赖于你对网络环境的理解以及程序使用者(包括那些居心叵测的用户)的使用技能。在这第三部分,Todd Sundsted安全讨论的最后一部分,他探究了这些问题并最后给出了解决方案。 在这个安全系列讲解中,我一直鼓励你从三个不同方面来考察JAVA安全问题。在头两篇文章中,我主要集中于虚拟机和应用程序安全。这个月,我将讨论最后一部分—“网络安全”。 网络安全处理的是互联的实体之间的通讯管道的安全问题――每个实体都确认来自另一方的身份验证以及基于通讯管道之上的信息真实性。 创建安全的网络程序会面临很多挑战。那些构成现代安全技术(比如加密系统)的论题常常令开发人员感到迷惑。并且,一些关键的标准和技术还是不透明的――比如X.509认证标准。时至今日,网络安全还是一个难题,因为,网络媒体本身的角色就难以理解。 看看下面这个推论:在我们日常交流中,沟通双方的信息交流通过多种媒介进行,比如光和声音。我们凭这些信息去判断他人的身份,鉴定沟通渠道的质量等。即使我们通过电话交流,我们还是可以通过对方在电话一端的语调,语速,走音等细微之处来辨别出信息,而不必通过交谈双方的谈话内容。 而基于如互联网等媒体的通讯则只能提供少的多的线索。设想你和同伴在两间屋子使用一种通话的罐来说话。可以想像,可怜的信号质量湮灭了那些我们借以做出判断的线索。而在互联网或是其它网络上的程序通讯同这种情况是类似的。 网络安全的内容包含了在匿名管道上进行身份验证,避免通讯信息遭到窃听以及意外或是恶意的修改等方面。 我广泛涉猎了用于加强安全通讯的工具以及相应技术(参考http://www.javaworld.com/javaworld/jw-08-2001/jw-0810-howto.html#resources)。这里我更实际的讨论在我们设计以及完成一个网络安全解决方案时所要考虑的事情。 理解你自己要保护什么: 设计一个安全解决方案你首先要从理解需求开始。通过互联网进行金融交易显然比你下载上周体育积分的WEB页面更需要安全。在选择一种技术和开始设计时,你应该考虑一下几个方面: • 安全设计会增加产品设计及实现的复杂性,以及安装,配置的复杂性,还有对于终端用户也是这样。尽管安全是值得的,但是复杂性则并不是用户所需要的。你打算怎样复杂化你的安全设计呢? • 安全处理,尤其是加密以及解密,常常都是CPU操作密集型的。多数桌面及服务器系统都有足够强的马力,但是那些缺乏资源的设备,比如蜂窝移动电话,PDAs等常常缺少这种能力。你的目标平台能适于处理这样的负荷吗? • 同样,安全设计会增加程序代码量。尽管在桌面以及服务器计算机上这个不算太严重的问题,但在嵌入式系统中,这就将会涉及到一些利害关系,特别是那些为JAVA2平台,比如Micro Edition (J2ME)而构建的应用,这样的情况下你又能处理好负荷吗? 比如这里的一个列子,移动信息设备框架(MIDP)第一版,就缺少SSL(安全套接口层)支持――端到端WEB解决方案中最核心的组件――其主要原因就是对于移动设备来说,SSL太过于苯重了。针对这个问题,SUN微系统实验室的Vipul Gupta为J2ME构建了兼容SSL标准的一个实现。他的这一成果表明了小设备也可以达到让人可以接受的SSL性能。Gupta的这一实现之所以能达到这一目标,是因为它只是支持最流行的密码套件,其余的则经过了削减以适应小设备的要求,当然,这种实现缺少服务器要求的客户端验证(一种很消耗的客户端组件),并且它通过多个到服务器的连接重复使用了RSA(Rivest-Shamir-Adleman)计算。你可以看看网址:http://www.javaworld.com/javaworld/jw-08-2001/jw-0810-howto.html#resources,可以找到更多的信息。 使用合适的技术: 选择一种合适的技术对于实现一种网络安全解决方案来说似乎已经不用多说了。这样的选择将会影响到安全的寿命和质量。JDK提供了大量的安全API函数。下面这张表将有助你为你的方案选择合适的技术。 • 验证和数字签名:JAVA密码系统(java.security) • 加密/解密和消息验证代码:JAVA密码系统扩展(javax.crypto) • X.509验证:JAVA密码系统(java.security.cert) • 可插入的验证和授权:JAVA验证和授权服务(javax.security.auth) JSK1.4测试版包括: • Kerberos:GSS(通用安全服务)API(org.ietf.jgss) • 证书路径确认:证书路径确认API(java.security.cert) 这些标准API处理了大量安全相关的WEB程序以及企业整合任务的问题。 理解网络: 不考虑网络来进行网络安全方案设计显然是不明智的。程序所运行的系统以及基于其上的网络都将在方案设计中给予充分的考虑。 设想一下这个情景:你建立了一个运行在安全网络之上的程序。如果网络确实是安全的――这意味着网络在物理上给保护起来,用户是可信赖的,并经过了仔细的授权――那么在这种情况下你就可以尽量少的关心你程序本身的安全问题。但是,在多数情况下,网络并非如所想像的那样安全,而且开发人员在开发安全系统中往往失败,因为不含安全机制的系统要比有安全机制的系统创建起来要难得多。然而,一些情况证实了这个方法。比如,在一个群集系统中运行了多个程序,并相互通讯,进行负载平衡,这样的情形就有足够的理由要求这个集群成为一个安全的整体,而不是程序本身。 更实际的讲,保护你的程序典型情况下意味着评估运行程序的机器的安全,机器安装环境的安全以及网络,包括接入点。 对接入点进行验证非常重要。对来自针对程序的恶意攻击,我们还可以设下“陷阱”,就是提供这样的一个入口,这个接入点为蛰伏的sniffer,嗅探器活动提供了一个窗口(sniffer是一种代码片断,用于侦听网络通信信息)。通过sniffer收集来的信息可以提供程序的入口。 理解合法使用者和滥用者: 你要记住,所谓的安全解决方案始终是围绕人来建立的,因此你必须理解程序使用者以及不怀好意者的能力和技术。那些“滥用者”,通常比正常用户更精于技术,他们让事情变得更复杂。 在你考虑设计你的程序安全方案时,你必须要考虑那些使用者的技能水平。比如,如果你的用户坚持要把密码记在碎纸上并在监视器上敲打进去,那么你就不必开发出强大的基于密码的安全系统。正如多数人所说,通常境况下,最好的安全是花费预算来进行培训。 对于滥用着来说,事情又有所不同。这些人常常更具有技术天赋,并更易于受到激励,这就要求更强的技术防护,即时的升级补丁包以及警醒的告诫。 全面掌握JAVA安全: 没有强大的网络安全,你的程序以及数据将是不稳定的。我讲过的其它的两部分――虚拟机安全,应用程序安全――和网络安全一起为JAVA程序提供了一个全面的安全图景。为了构建安全的JAVA程序,你必须全面理解以上的三个方面。 <

小小豆叮

常用的查看Oracle数据库的SQL

1、查看表空间的名称及大小 select t.tablespace_name, round(sum(bytes/(1024*1024)),0) ts_size from dba_tablespaces t, dba_data_files d where t.tablespace_name = d.tablespace_name group by t.tablespace_name; 2、查看表空间物理文件的名称及大小 select tablespace_name, file_id, file_name, round(bytes/(1024*1024),0) total_space from dba_data_files order by tablespace_name; 3、查看回滚段名称及大小 select segment_name, tablespace_name, r.status, (initial_extent/1024) InitialExtent,(next_extent/1024) NextExtent, max_extents, v.curext CurExtent From dba_rollback_segs r, v$rollstat v Where r.segment_id = v.usn(+) order by segment_name ; 4、查看控制文件 select name from v$controlfile; 5、查看日志文件 select member from v$logfile; 6、查看表空间的使用情况 select sum(bytes)/(1024*1024) as free_space,tablespace_name from dba_free_space group by tablespace_name; SELECT A.TABLESPACE_NAME,A.BYTES TOTAL,B.BYTES USED, C.BYTES FREE, (B.BYTES*100)/A.BYTES "% USED",(C.BYTES*100)/A.BYTES "% FREE" FROM SYS.SM$TS_AVAIL A,SYS.SM$TS_USED B,SYS.SM$TS_FREE C WHERE A.TABLESPACE_NAME=B.TABLESPACE_NAME AND A.TABLESPACE_NAME=C.TABLESPACE_NAME; 7、查看数据库库对象 select owner, object_type, status, count(*) count# from all_objects group by owner, object_type, status; 8、查看数据库的版本  Select version FROM Product_component_version Where SUBSTR(PRODUCT,1,6)='Oracle'; 9、查看数据库的创建日期和归档方式 Select Created, Log_Mode, Log_Mode From V$Database; <

小小豆叮

全面保护你的Java程序安全(上)

第一部分:Java的安全基础——虚拟机和字节码安全 概论:安全问题对很多数人来说都非常重要。从其历史看,Java安全主要意味着虚拟机和字节码安全。然而这个看法忽略了两个重要方面—应用程序和网络安全。在下面一系列文章中,Todd Sundsted讲解了JAVA虚拟机安全,应用程序安全,网络安全,解释了应该采取什么样的措施来全面巩固你的Java安全。在这第一部分,他向我们解释了Java安全的基础:虚拟机和字节码安全。 “似乎还没有人曾因为写出了不安全的Java代码而遭解雇”。这句话是我对那句流行语“没人曾因购买了IBM而遭解雇”的修正版本。那些更关心网络速度和那些更有兴趣为简历添加更多有价值项目的雇员常常犯下安全问题。 再来看看另一个令人担心的现象:在我同管理人员和工程技术人员谈论安全问题时,我常常发现他们对自己的行为存在一些误解,他们认为不必考虑安全问题,因为“Java本身就等于安全”。在这样错误观念的指引下,工程师们没有去考虑以下三个方面的安全问题:虚拟机安全,应用程序安全,网络安全。 在以下一系列文章中,我会尽力修正这种错误见解。接下来,我将就三方面的问题来对Java安全进行讨论,并举列说明一般安全问题是怎样窃入的。另外我也会介绍一些办法来创建安全的应用程序。 ·三种安全问题: 在Java初次露面时,开发者,研究人员,新闻媒体界对其安全问题就反响剧烈。在早前的时候,Java安全就是意味着字节码安全和虚拟机安全。由于Java过去主要是作为下载到本地执行的小应用程序开发语言,下载下来的代码的安全性和执行环境就是异常重要的事情。这种情况下的安全意味着正确安装类装载器和安全管理器以及验证下载的代码。 在我以前开发C/C++程序的数年里,我从没担心过虚拟机安全问题—这个问题完全是随着Java而成了人们关注的中心。谈到安全问题,我担心的总是应用程序漏洞或是危及程序或系统安全的执行情况。在C++领域,应用程序上的安全包括限制“setuid”代码范围(在Unix环境,setuid代码是作为另外的用户进程来运行—典型的情况是超级用户)并力图避免缓冲溢出及其它类型的堆栈问题。 而分布式应用程序的引入则带来了另外一些方面的问题。正如其名字所示,分布式程序由多个部分组成,每个部分都驻留在它自己的机器上,并通过公共网络和其它部分通信。一个Web应用就是典型的列子。在网络意义上的安全则意味着签名,授权,应用程序组件,加密通信管道等。 许多开发人员并不清楚以上几方面的不同,并以为Java在虚拟机一层安全了,那么整个应用程序就安全了。我很希望改变这种观念。下面就开始来讨论Java的虚拟机安全。 ·安全基础:虚拟机安全 虚拟机安全,长期以来一直是开发人员注意的焦点,几乎直到现在也还是没有结果。 我最初对讨论虚拟机安全感到有兴趣是在转向应用程序和网络安全之前。我决定给予它同另两个部分同样公平的时间来讨论,这出于两个理由:首先,优秀的编程教材因该包含过去6年来发现过的大量漏洞,第二,很多安全问题跨越了我要讨论的三个方面。为了能透彻理解,你必须要全面熟悉三个方面,包括Java虚拟机安全。 如果你检查过去6年发现的各种安全问题(看http://www.javaworld.com/javaworld/jw-06-2001/jw-0615-howto.html#resources的官方清单),你将发现它们被分成一系列目录。就所关注的虚拟机安全来讲,最重要的两种安全漏洞都是围绕着未被验证和可能非法的字节码以及Java类型系统破坏来展开。在实际开发中,这两者经常是关联在一起 ·未验证代码探秘 在JVM通过网络从服务器上下载类代码时,它并没有办法知道这些字节码是否能安全执行。安全的字节码永不会指示虚拟机执行让Java运行时处于不懈调和无效的状态。 通常,Java编译器可以确保创建的类文件里的字节码是安全的。然而也可以手工写出Java编译器不允许的字节码。Java校验器以一系列极富想像力的方法检查所有这样的字节码并验证那些不合规范的代码。一旦校验完成,JVM便知道程序代码是安全的—只要校验器正常工作。 下面让我们来看看一个列子,以更好的理解校验器所扮演的角色,并看看一旦校验器失效会产生什么后果。 考虑一下下面这个类: public class Test1 { public static void main(String [] arstring) { Float a = new Float(56.78); Integer b = new Integer(1234); System.out.println(a.toString()); }  } 当你写完它并运行,程序将向屏幕打印出字符串“56.78”。这是个在类里分配的一个浮点型变量。我们即将修改一处代码,欺骗虚拟机在整型变量上激活toString()方法而不是浮点型变量(你可以从网址下载并修改源代http://www.javaworld.com/javaworld/jw-06-2001/jw-0615-howto.html#resources)。 再来看看这段经反编译后的代码的输出: Method void main(java.lang.String[]) 0 new #3 3 dup 4 ldc2_w #13 7 invokespecial #8 10 astore_1 11 new #4 14 dup 15 sipush 1234 18 invokespecial #9 21 astore_2 22 getstatic #10 25 aload_1 26 invokevirtual #12 29 invokevirtual #11 32 return 上面的代码包含了main()函数的反编译输出。在这个方法的地址偏移量25处,虚拟机载入于偏移0到10处创建的浮点型变量的一个引用。这就是我们要修改的地方。 下面就是经修改后的反编译代码: Method void main(java.lang.String[]) 0 new #3 3 dup 4 ldc2_w #13 7 invokespecial #8 10 astore_1 11 new #4 14 dup 15 sipush 1234 18 invokespecial #9 21 astore_2 22 getstatic #10 25 aload_2 26 invokevirtual #12 29 invokevirtual #11 32 return 这个类在偏移量25处的字节码是完全相同的,载入一个整型变量的引用。 注意看看,修改后的代码仍然是安全的,这非常重要,这意味着JVM仍然将执行代码而不会崩溃或是将错误代码隔离开。然而校验器仍然能分辨出这些变化。在我的系统里,在我运行这片代码时,出现错误:  Exception in thread "main" java.lang.VerifyError: (class: Test1, method: main signature: ([Ljava/lang/String;)V) Incompatible object argument for function call 如果你关掉校验器或是你找到一处虚拟机漏洞并非常规地通过了校验器的检查,那非法代码就要启动了。执行下面的命令,我接收到值:1234—整型变量值。 java -noverify Test1 这个列子并无多大害处,但潜在的危害确是巨大的。以上这样的技术如果同虚拟机漏洞联系起来,造成未被检查的代码得以执行,那么这将造成严重的类型混乱。 ·类型混乱 类型的概念对java编程语言来说是浑然一体的。每个值都同一种类型相关联,JVM就是用值的类型来决定什么样的操作可以作用在什么样的值上。 程序的类型信息对于虚拟机安全是至关重要的。一个被恶意的,未经验证的代码启动的类型混淆攻击会试图让JVM相信伪装成为一个类实列的内存块确实是是另一个类的实列,以此进行攻击。如果攻击成功,程序就会以设计者意想不到的方式来操作类实列。这种攻击称为“类型混淆攻击”,因为虚拟机已经闹不清被修改的类的类型。 如果类经过了完全的验证,那么“类型混淆攻击”是不会发生的。在上面的第二个列表中,校验器捕获了这个企图并抛出了异常。也就是说,只要校验器没有被关闭或是被绕过,那么安全就是能够保障的。 幸运的是,我所担心的Java字节码校验器最后的一个漏洞在1999年末被发现。基于这个事实,你可能会认为自己不会在陷入危险中,然而,这过于疏忽大意了。 虽然漏洞越来越少,但还是有充足的机会留给狡猾的代码混入程序之中。记住,你可以手工关闭校验器检验。在接下来的文章中中,我列举出三种主要的java程序,以向大家示列在怎样的环境下关掉校验器。其中一个程序有一个重要的RMI(远程方法调用)组件(如你以后将要学到的,RMI可以让类通过网络载入到程序中,并让你的程序失控)。如果你能避免这种情况发生,就不要关掉校验器验证。 JVM安全是java安全体系中非常重要的一方面。这些未验证代码和类型混淆方面的讨论将有助于你理解为什么。对于下载代码和类型系统来说,没有适当的校验保证,安全计算将成为一句空话。 下次,我们将探索另一方面的java安全:应用程序安全。 <

小小豆叮

改进Java的字符串分解器

一、概述   大多数Java程序员都曾经使用过java.util.StringTokenizer类。它是一个很方便的字符串分解器,主要用来根据分隔符把字符串分割成标记(Token),然后按照请求返回各个标记。这个过程称为Tokenization,实际上就是把字符序列转换成应用程序能够理解的多个标记。   虽然StringTokenizer用起来很方便,但它的功能却很有限。这个类只是简单地在输入字符串中查找分隔符,一旦找到了分隔符就分割字符串。它不会检查分隔符是否在子串之中这类条件,当输入字符串中出现两个连续的分隔符时,它也不会返回""(字符串长度为0)形式的标记。   为了突破这些局限,Java 2平台提供了BreakIterator类,它是在StringTokenizer之上改进的字符串分解器。由于JDK 1.1.x没有提供这个类,为了满足自己的需要,开发者经常花费很多时间从头开始编写分解器。在涉及到数据格式化处理的大型工程中,这类定制的字符串分解器有时随处可见,而且这种情况并不罕见。   本文的目标是帮助你利用现有的StringTokenizer类,编写一个高级字符串分解器。 二、StringTokenizer的局限   你可以用以下三种构造函数中的任意一种创建StringTokenizer分解器: StringTokenizer(String sInput):以空白字符(“ ”,“\t”,“\n”)为分隔符分割字符串。 StringTokenizer(String sInput, String sDelimiter):以sDelimiter为分隔符分割字符串。 StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens):以sDelimiter为分隔符分割字符串,但如果bReturnTokens为true,则分隔符也作为标记返回。   第一个构造函数不检查输入字符串是否包含子串。例如,如果以空白字符为分隔符分割“hello. Today \"I am \" going to my home town”,则字符串分解结果是hello.、Today、"I、am、"、going等,而不是hello.、Today、"I am "、going等。   第二个构造函数不检查两个分隔符连续出现的情况。例如,如果以“,”为分隔符分割“book, author, publication,,,date published”这个字符串,则StringTokenizer返回book、author、publication和date published这四个标记,而不是book、author、publication、""、""和date published这6个标记(其中""表示0长度字符串)。要得到6个标记的答案,你必须把StringTokenizer的bReturnTokens参数设置为true。   允许设置值为true的bReturnTokens参数是一个重要的功能,因为它考虑到了分隔符连续出现的情况。例如,使用第二个构造函数时,如果数据是动态收集得到而且要用来更新数据库中的表,输入字符串中的标记对应着表里面列的值,那么当我们不能确定哪一个列应该设置为""时,我们就无法把输入串中的标记映射到数据库列。假设我们要把记录插入到一个有6个列的表,而输入数据中包含两个连续的分隔符。此时,StringTokenizer的分解结果是5个标记(两个连续的分隔符代表""标记,它将被StringTokenizer忽略),而我们却有6个字段需要设置。同时,我们也不知道连续分隔符在哪里出现,所以也就不知道哪一个列应该设置成""。   当标记本身等同于分隔符(无论是长度还是值)且位于子串之内时,第三个构造函数无效。例如,如果我们要以“,”为分隔符分解字符串“book, author, publication,\",\",date published”(这个字符串包含一个“,”标记,它与分隔符一样),结果是book、author、publication、"、"、date published这六个标记,而不是book、author、publication、,(逗号字符)、date published这五个标记。再提醒一下,即使我们把StringTokenizer的bReturnTokens参数设置设置成了true,在这种情况下也没有什么帮助。 三、高级字符串分解器   在编写代码之前,你必须搞清楚一个好的分解器有哪些基本要求。因为Java开发者已经习惯于使用StringTokenizer类,所以一个好的分解器应该提供StringTokenizer类提供的所有实用方法,比如hasMoreTokens()、nextToken()、countTokens()。   本文提供的代码很简单,而且大部分代码足以自我解释。在这里,我主要利用了StringTokenizer类(创建类实例时bReturnTokens参数设置为true),并提供了上面提到的几个方法。大多数时候标记与分隔符不同,有些时候分隔符却要作为标记输出(尽管非常罕见),此时如果出现了对标记的请求,分解器要把分隔符作为标记输出。创建PowerfulTokenizer对象时,你只需要提供输入字符串和分隔符这两个参数,PowerfulTokenizer将在内部使用bReturnTokens设置成true的StringTokenizer。(这么做的原因在于,如果不是用bReturnTokens设置成true的方式创建StringTokenizer,那么它将在解决先前提出的问题时受到限制)。为了正确地控制分解器,代码在几个地方(计算标记的总数量以及nextToken())检查bReturnTokens是否设置成了true。   你可能已经发现,PowerfulTokenizer实现了Enumeration接口,从而也就实现了hasMoreElements()和nextElement()这两个方法,而这两个方法又分别把调用直接委托给hasMoreTokens()和nextToken()。(由于实现了Enumeration接口,PowerfulTokenizer实现了与StringTokenizer的向后兼容。)   我们来看一个例子,假设输入字符串是“hello, Today,,, \"I, am \", going to,,, \"buy, a, book\"”,分隔符是“,”。用分解器分割这个字符串时返回结果如表1所示: 表1:字符串分解结果   输入字符串包含11个逗号(,)字符,其中3个在子串里面、4个连续出现(“Today,,,”中包含两个连续逗号,第一个逗号是Today的分隔符)。下面是PowerfulTokenizer计算标记总数的算法: 如果bReturnTokens=true,把子串中的分隔符数量乘以2,再从实际总数量减去该数字,就得到了标记的总数。理由是,对于子串“buy, a, book”,StringTokenizer将返回5个标记(即“buy:,:a:,:book”),而PowerfulTokenizer将返回一个标记(即“buy, a, book”),两者的差值是4(即,2乘以子串中的分隔符数量)。这个公式对于所有包含分隔符的子串都有效。 类似地,对于bReturnTokens=false的情形,我们从实际总数(19)减去表达式[分隔符总数(11)- 连续分隔符数量(4) + 子串中的分隔符数量(3)]。由于这时我们不返回分隔符,它们(非连续出现或在子串内部)对我们来说没有用,上面的公式为我们返回了标记的总数量(9)。   请记住这两个公式,它们是PowerfulTokenizer的核心。这两个公式适用于几乎所有它们各自条件下的情形。但是,如果你有更复杂的要求,不能使用这两个公式,那么你应该在编写代码之前分析各种可能出现的情况,并设计出自己的公式。 // 检查分隔符是否位于子串之内 for (int i=1; i/td> { iIndex = sInput.indexOf(sDelim, iIndex+1); if (iIndex == -1) break; // 如果分隔符位于子串之内,则向前分析直至子串结束 while (sInput.substring(iIndex-iLen, iIndex).equals(sDelim)) { iNextIndex = sInput.indexOf(sDelim, iIndex+1); if (iNextIndex == -1) break; iIndex = iNextIndex; } aiIndex[i] = iIndex; //System.out.println("aiIndex[" + i + "] = " + iIndex); if (isWithinQuotes(iIndex)) { if (bIncludeDelim) iTokens -= 2; else iTokens -= 1; } }   countTokens()方法检查子串是否包含双引号。如果包含,那么它减少总数并把索引值修改为字符串中下一个双引号出现的位置(如上面的代码片断所示)。如果bReturnTokens是false,那么它从总数减去输入字符串中出现的非连续分隔符的数量。 // 如发现多个连续的分隔符,则返回""作为标记 if ( (sPrevToken.equals(sDelim)) && (sToken.equals(sDelim)) ) { sPrevToken = sToken; iTokenNo++; return ""; } // 检查标记本身是否等于分隔符 if ( (sToken.trim().startsWith("\"")) && (sToken.length() == 1) ) { // 标记本身等于分隔符的特殊情况 String sNextToken = oTokenizer.nextToken(); while (!sNextToken.trim().endsWith("\"")) { sToken += sNextToken; sNextToken = oTokenizer.nextToken(); } sToken += sNextToken; sPrevToken = sToken; iTokenNo++; return sToken.substring(1, sToken.length()-1); } // 检查字符串中是否包含子串 else if ( (sToken.trim().startsWith("\"")) && (!((sToken.trim().endsWith("\"")) && (!sToken.trim().endsWith("\"\"")))) ) { if (oTokenizer.hasMoreTokens()) { String sNextToken = oTokenizer.nextToken(); // 检查"\"\"" while (!((sNextToken.trim().endsWith("\"")) && (!sNextToken.trim().endsWith("\"\""))) ) { sToken += sNextToken; if (!oTokenizer.hasMoreTokens()) { sNextToken = ""; break; } sNextToken = oTokenizer.nextToken(); } sToken += sNextToken; } }   nextToken()方法通过StringTokenizer.nextToken方法获取标记,并检查标记中的双引号字符。如果发现了这些字符,它继续获取标记直至不能再找到带有双引号的标记。另外,它还把标记保存到一个变量(sPrevToken,参见本文后面完整的源代码)以检查连续出现的分隔符。如果nextToken()发现等同于分隔符的连续多个标记,那么它返回""(长度为0的字符串)作为标记。   按照类似的方法,hasMoreTokens()方法检查已经返回的标记数量是否小于标记的总数量。   【结束语】本文为你介绍了如何轻松地编写一个强大的字符串分解器。根据本文介绍的原理,你能够迅速编写出复杂的字符串分解器,节省大量的开发时间。   请从这里下载本文的完整代码。 <

小小豆叮

在Java中监控文本框的变化

作为一个跨平台的编程解决方案,Java显然不能像Delphi那样,在用户界面设计方面提供强大、直观和快捷的设计支持。比如对于文本框的控制,当我们要在程序中感知用户是否修改了文本框中的内容时,Delphi提供了一个直接的事件调用OnValueChanged(),可以在文本框内容得到实际的改动时被激活。而要在Java中实现这一功能就似乎麻烦了一点,直接的调用只有keyPressed()和keyTyped(),前者只对主键盘区(字符、数字等)有反应,对于Delete等功能键没有反应,而后者又似乎反应太过灵敏,对一些不会改变文本框内容的功能键也积极响应。   那么怎样对Java中的文本框设置类似OnValueChanged()的事件处理呢?这首先取决于我们所使用的文本框是属于AWT类还是Swing类。AWT(Abstract Window Toolkit:抽象窗口工具箱)最初是为了让Java具有UI设计能力而编写的,但在1.0版本中并不被叫好。到了Java 1.1版本之后,由于加入了新的事件驱动方法,才真正变得实用、方便和稳定起来。而Swing类则是为了应付AWT存在的不足,在Java 1.1之后推出的一个组件库,由于是建立在Bean的基础上(Swing的组件是Bean),所以相对AWT而言,它是一个“轻量级”的选手。Swing更“自然地”支持更多的面向对象的事件驱动,设计出的UI外观可以在不同的平台上和操作系统上被动态地改变。但在某些场合下,由于其严谨的封装特性,具体实现过程反而显得较AWT类要冗长一点。显然,如果不考虑对老代码的继续使用,Swing类应该是设计UI的首选。 使用AWT类   对于AWT中的TextField类,实现监控的关键是对TextListener的使用。TextListener的声明如下:   interface TextListener extends EventListener   它在java.awt.event包中被定义。这个接口是提供给用户用以监听文本内容的变化的。它所包含的方法是textValueChanged(),完整的声明如下:   public void textValueChanged(TextEvent e) {}   当一个对象中的文本内容发生变化时,就会触发该事件,并执行该方法中所指定的语句。要注意的是:TextListener是一个接口(interface),必须先定义一个新类来执行(implements)它。本文所定义的新类名为AWT_OnValueChanged。   在窗体的说明语句中,为TextField增加一个TextListener事件(本文给出的TextField对象名为textField1): textField1.addTextListener(new AWT_OnValueChanged());   最后对textValueChanged()事件进行重载:   public void textValueChanged(TextEvent e)   {    //写入实际代码,实现所需功能 ……   } 使用Swing类   对于Swing中的JTextField类,实现监控的过程则相对复杂一些。JTextField中没有设置TextListener,而是将对文本的监视任务放入了另外一个接口Document中。因此首先要为JTextField对象申请一个Document接口对象,使用的方法是JTextField1.getDocument()(本文给出的JTextField对象名为JTextField1)。获得Document后,就可以使用addDocumentListener()来得到一个和TextListener功能类似的监听接口。DocumentListener的完整声明如下:   interface DocumentListener extends EventListener   它在包java.swing.event.DocumentListener中定义,其中包含了三个方法:    <

小小豆叮

Java2下Applet数字签名具体实现方法

自从Java技术开始应用以来,人们对Java平台的安全性以及由于部署Java技术所引发的安全问题给予了极大的关注。特别是在1998年11月Java2发布后,Java的安全体系结构发生了根本的改进,对于终端用户而言,它可以保护文件和私人数据不被恶意的程序或病毒感染和破坏,鉴别代码提供者的身份。对于开发者而言,通过使用API方法,能够将安全性功能集成到应用程序中,因为API的体系结构能够定义和集成对特定的资源的使用权限、加密、安全性管理、策略管理,并提供了一些类来管理公钥/密钥对及信任用户群的公钥证书。同时系统管理员、开发者和用户可以使用它提供的工具管理钥匙库,在JAR文件中生成数字签名、签名的完整性检测、创建和修改策略文件。按照Java设计者的观点,Java安全包括2个方面的内容,首先将Java作为一种安全的平台提供给用户,在此平台上,可安全地运行Java程序;其次提供用Java编程语言实现的安全工具和服务,它使得诸如企业界这样一些对安全非常敏感的领域也可应用Java技术。本文将就这二个方面介绍Java2的安全性新特性以及该新特性下的Applet数字签名的具体实现方法。   Java2采用了如图1所示的新的安全体系结构,并基于这种安全体系结构提供了很多新特性。 1.1 密纹访问控制   这种能力从一开始就在JDK中存在。但要使用它,应用程序的编写者不得不做大量的编程工作 <

小小豆叮

谈谈Java语言的垃圾收集器

垃圾收集器是Java语言区别于其他程序设计语言的一大特色。它把程序员从手工回收内存空间的繁重工作中解脱了出来。在SUN公司的Java程序员(Java Programmer)认证考试中,垃圾收集器是必考的内容,一般最多可以占总分值的6%左右。但是由于SUN公司的Java Programming Language SL-275 课程的标准教材中,对有关垃圾收集器的内容只做了非常简单的介绍,而另外的一些关于Java技术的书籍,比如《Java 2 核心技术》(Core Java 2)、《Java编程思想》(Thinking in Java)、《精通Java 2》等等,里面关于垃圾收集器的内容也几乎没有,或者只是简单地提两句,所以很多参加Java Programmer认证考试的中国考生,在垃圾收集器这一部分的得分都为0分(笔者曾认识一位SUN公司授权的中国Java培训班的老师,其考试总分为89%,但垃圾收集器的部分竟然也为0分)。鉴于此,笔者总结了这个垃圾收集器的专题,希望对广大Java技术的爱好者和准备认证考试的考生们有所帮助。 我们知道,许多程序设计语言都允许在程序运行期动态地分配内存空间。分配内存的方式多种多样,取决于该种语言的语法结构。但不论是哪一种语言的内存分配方式,最后都要返回所分配的内存块的起始地址,即返回一个指针到内存块的首地址。 当已经分配的内存空间不再需要时,换句话说当指向该内存块的句柄超出了使用范围的时候,该程序或其运行环境就应该回收该内存空间,以节省宝贵的内存资源。 在C,C++或其他程序设计语言中,无论是对象还是动态配置的资源或内存,都必须由程序员自行声明产生和回收,否则其中的资源将消耗,造成资源的浪费甚至死机。但手工回收内存往往是一项复杂而艰巨的工作。因为要预先确定占用的内存空间是否应该被回收是非常困难的!如果一段程序不能回收内存空间,而且在程序运行时系统中又没有了可以分配的内存空间时,这段程序就只能崩溃。通常,我们把分配出去后,却无法回收的内存空间称为"内存渗漏体(Memory Leaks)"。 以上这种程序设计的潜在危险性在Java这样以严谨、安全著称的语言中是不允许的。但是Java语言既不能限制程序员编写程序的自由性,又不能把声明对象的部分去除(否则就不是面向对象的程序语言了),那么最好的解决办法就是从Java程序语言本身的特性入手。于是,Java技术提供了一个系统级的线程(Thread),即垃圾收集器线程(Garbage Collection Thread),来跟踪每一块分配出去的内存空间,当Java 虚拟机(Java Virtual Machine)处于空闲循环时,垃圾收集器线程会自动检查每一快分配出去的内存空间,然后自动回收每一快可以回收的无用的内存块。 垃圾收集器线程是一种低优先级的线程,在一个Java程序的生命周期中,它只有在内存空闲的时候才有机会运行。它有效地防止了内存渗漏体的出现,并极大可能地节省了宝贵的内存资源。但是,通过Java虚拟机来执行垃圾收集器的方案可以是多种多样的。 下面介绍垃圾收集器的特点和它的执行机制: 垃圾收集器系统有自己的一套方案来判断哪个内存块是应该被回收的,哪个是不符合要求暂不回收的。垃圾收集器在一个Java程序中的执行是自动的,不能强制执行,即使程序员能明确地判断出有一块内存已经无用了,是应该回收的,程序员也不能强制垃圾收集器回收该内存块。程序员唯一能做的就是通过调用System. gc 方法来"建议"执行垃圾收集器,但其是否可以执行,什么时候执行却都是不可知的。这也是垃圾收集器的最主要的缺点。当然相对于它给程序员带来的巨大方便性而言,这个缺点是瑕不掩瑜的。 垃圾收集器的主要特点有: 1.垃圾收集器的工作目标是回收已经无用的对象的内存空间,从而避免内存渗漏体的产生,节省内存资源,避免程序代码的崩溃。 2.垃圾收集器判断一个对象的内存空间是否无用的标准是:如果该对象不能再被程序中任何一个"活动的部分"所引用,此时我们就说,该对象的内存空间已经无用。所谓"活动的部分",是指程序中某部分参与程序的调用,正在执行过程中,尚未执行完毕。 3.垃圾收集器线程虽然是作为低优先级的线程运行,但在系统可用内存量过低的时候,它可能会突发地执行来挽救内存资源。当然其执行与否也是不可预知的。 4.垃圾收集器不可以被强制执行,但程序员可以通过调用System. gc方法来建议执行垃圾收集器。 5.不能保证一个无用的对象一定会被垃圾收集器收集,也不能保证垃圾收集器在一段Java语言代码中一定会执行。因此在程序执行过程中被分配出去的内存空间可能会一直保留到该程序执行完毕,除非该空间被重新分配或被其他方法回收。由此可见,完全彻底地根绝内存渗漏体的产生也是不可能的。但是请不要忘记,Java的垃圾收集器毕竟使程序员从手工回收内存空间的繁重工作中解脱了出来。设想一个程序员要用C或C++来编写一段10万行语句的代码,那么他一定会充分体会到Java的垃圾收集器的优点! 6.同样没有办法预知在一组均符合垃圾收集器收集标准的对象中,哪一个会被首先收集。 7.循环引用对象不会影响其被垃圾收集器收集。 8.可以通过将对象的引用变量(reference variables,即句柄handles)初始化为null值,来暗示垃圾收集器来收集该对象。但此时,如果该对象连接有事件监听器(典型的 AWT组件),那它还是不可以被收集。所以在设一个引用变量为null值之前,应注意该引用变量指向的对象是否被监听,若有,要首先除去监听器,然后才可以赋空值。 9.每一个对象都有一个finalize( )方法,这个方法是从Object类继承来的。 10.finalize( )方法用来回收内存以外的系统资源,就像是文件处理器和网络连接器。该方法的调用顺序和用来调用该方法的对象的创建顺序是无关的。换句话说,书写程序时该方法的顺序和方法的实际调用顺序是不相干的。请注意这只是finalize( )方法的特点。 11.每个对象只能调用finalize( )方法一次。如果在finalize( )方法执行时产生异常(exception),则该对象仍可以被垃圾收集器收集。 12.垃圾收集器跟踪每一个对象,收集那些不可到达的对象(即该对象没有被程序的任何"活的部分"所调用),回收其占有的内存空间。但在进行垃圾收集的时候,垃圾收集器会调用finalize( )方法,通过让其他对象知道它的存在,而使不可到达的对象再次"复苏"为可到达的对象。既然每个对象只能调用一次finalize( )方法,所以每个对象也只可能"复苏"一次。 13.finalize( )方法可以明确地被调用,但它却不能进行垃圾收集。 14.finalize( )方法可以被重载(overload),但只有具备初始的finalize( )方法特点的方法才可以被垃圾收集器调用。 15.子类的finalize( )方法可以明确地调用父类的finalize( )方法,作为该子类对象的最后一次适当的操作。但Java编译器却不认为这是一次覆盖操作(overriding),所以也不会对其调用进行检查。 16.当finalize( )方法尚未被调用时,System. runFinalization( )方法可以用来调用finalize( )方法,并实现相同的效果,对无用对象进行垃圾收集。 17.当一个方法执行完毕,其中的局部变量就会超出使用范围,此时可以被当作垃圾收集,但以后每当该方法再次被调用时,其中的局部变量便会被重新创建。 18.Java语言使用了一种"标记交换区的垃圾收集算法"。该算法会遍历程序中每一个对象的句柄,为被引用的对象做标记,然后回收尚未做标记的对象。所谓遍历可以简单地理解为"检查每一个"。 19.Java语言允许程序员为任何方法添加finalize( )方法,该方法会在垃圾收集器交换回收对象之前被调用。但不要过分依赖该方法对系统资源进行回收和再利用,因为该方法调用后的执行结果是不可预知的。 通过以上对垃圾收集器特点的了解,你应该可以明确垃圾收集器的作用,和垃圾收集器判断一块内存空间是否无用的标准。简单地说,当你为一个对象赋值为null并且重新定向了该对象的引用者,此时该对象就符合垃圾收集器的收集标准。 判断一个对象是否符合垃圾收集器的收集标准,这是SUN公司程序员认证考试中垃圾收集器部分的重要考点(可以说,这是唯一的考点)。所以,考生在一段给定的代码中,应该能够判断出哪个对象符合垃圾收集器收集的标准,哪个不符合。下面结合几种认证考试中可能出现的题型来具体讲解: Object obj = new Object ( ) ; 我们知道,obj为Object的一个句柄。当出现new关键字时,就给新建的对象分配内存空间,而obj的值就是新分配的内存空间的首地址,即该对象的值(请特别注意,对象的值和对象的内容是不同含义的两个概念:对象的值就是指其内存块的首地址,即对象的句柄;而对象的内容则是其具体的内存块)。此时如果有 obj = null; 则obj指向的内存块此时就无用了,因为下面再没有调用该变量了。 请再看以下三种认证考试时可能出现的题型: 程序段1: 1.fobj = new Object ( ) ; 2.fobj. Method ( ) ; 3.fobj = new Object ( ) ; 4.fobj. Method ( ) ; 问:这段代码中,第几行的fobj 符合垃圾收集器的收集标准? 答:第3行。因为第3行的fobj被赋了新值,产生了一个新的对象,即换了一块新的内存空间,也相当于为第1行中的fobj赋了null值。这种类型的题在认证0考试中是最简单的。 程序段2: 1.Object sobj = new Object ( ) ; 2.Object sobj = null ; 3.Object sobj = new Object ( ) ; 4.sobj = new Object ( ) ; 问:这段代码中,第几行的内存空间符合垃圾收集器的收集标准? 答:第1行和第3行。因为第2行为sobj赋值为null,所以在此第1行的sobj符合垃圾收集器的收集标准。而第4行相当于为sobj赋值为null,所以在此第3行的sobj也符合垃圾收集器的收集标准。 如果有一个对象的句柄a,且你把a作为某个构造器的参数,即 new Constructor ( a )的时候,即使你给a赋值为null,a也不符合垃圾收集器的收集标准。直到由上面构造器构造的新对象被赋空值时,a才可以被垃圾收集器收集。 程序段3: 1.Object aobj = new Object ( ) ; 2.Object bobj = new Object ( ) ; 3.Object cobj = new Object ( ) ; 4.aobj = bobj; 5.aobj = cobj; 6.cobj = null; 7.aobj = null; 问:这段代码中,第几行的内存空间符合垃圾收集器的收集标准? 答:第7行。注意这类题型是认证考试中可能遇到的最难题型了。 行1-3分别创建了Object类的三个对象:aobj,bobj,cobj 行4:此时对象aobj的句柄指向bobj,所以该行的执行不能使aobj符合垃圾收集器的收集标准。 行5:此时对象aobj的句柄指向cobj,所以该行的执行不能使aobj符合垃圾收集器的收集标准。 行6:此时仍没有任何一个对象符合垃圾收集器的收集标准。 行7:对象cobj符合了垃圾收集器的收集标准,因为cobj的句柄指向单一的地址空间。在第6行的时候,cobj已经被赋值为null,但由cobj同时还指向了aobj(第5行),所以此时cobj并不符合垃圾收集器的收集标准。而在第7行,aobj所指向的地址空间也被赋予了空值null,这就说明了,由cobj所指向的地址空间已经被完全地赋予了空值。所以此时cobj最终符合了垃圾收集器的收集标准。 但对于aobj和bobj,仍然无法判断其是否符合收集标准。 总之,在Java语言中,判断一块内存空间是否符合垃圾收集器收集标准的标准只有两个: 1.给对象赋予了空值null,以下再没有调用过。 2.给对象赋予了新值,既重新分配了内存空间。 最后再次提醒一下,一块内存空间符合了垃圾收集器的收集标准,并不意味着这块内存空间就一定会被垃圾收集器收集。 <

小小豆叮

Java、Java Applet与 JavaScript间的通信

摘 要:本文着重阐述了网页开发中,通过灵活使用从JavaScript语言中访问Java的方法、从JavaScript中访问JavaScript小程序的方法与变量,以及在Java Applet小程序中使用JavaScript等技术,实现这几种网页开发语言的互相补充,以开发更完美的Web应用程序。 JavaScript是用于HTML环境的开发语言,提供了能够响应Web页面事件的脚本,可以完全访问浏览器窗口的各个方面,善于合并HTML、Java Applet小程序、插入件、服务器方程序和其他Web组件,形成完全集成的Web应用程序。而Java是功能强大的著名开发语言,能够支持Web应用程序的开发,用于开发高级Web对象,并提供实现嵌入Web页面的可执行内容,具有更强的编程功能,可以作为JavaScript功能的良好补充,只不过这些功能被限制在有限的浏览器窗口区中。 Java与JavaScript可以互相补充,以开发功能更完美的Web应用程序。本文归纳了笔者编程中曾使用过的,涉及到有关JavaScript与Java、Java Applet小程序之间互访的问题的一些方法,仅供参考。 一、从JavaScript中访问Java方法 在HTML脚本中可以用JavaScript直接调用Java中的方法,只需要在调用语句前用“java.lang.”加以表示即可。具体语句用法如下例所示: java.Lang.System.Out.println(“Hello!”) 但此种方法只适用于Netscape Navigator,一般不提倡在Web应用程序中使用。 二、从JavaScript中访问Java Applet小程序中的方法和变量 通过JavaScript提供的Applet对象,JavaScript代码可以访问Java的变量和方法,具体步骤和用法示例如下。需要注意的是,JavaScript提供的applet对象具有name属性,而没有方法和事件处理器。 步骤: 1) 将要访问的Java Applet小程序的方法和变量声明为Public,且必须在Public类中声明; 2) Java Applet小程序要先装入才能访问,尽管applet对象没有定义onLoad事件,但可以在HTML文档的〈body〉标志中,指定使用Window对象的onLoad事件处理器; 3) Java Applet小程序可以用JavaScript的applet对象来访问。 示例: “mytest.htm” //通过调用accessApplet()装入小程序 “Testtext.java” import java.applet.*; …… public class Testtext extends Applet { …… public void setText(String s) //setText()必须声明为“public” { text=s; repaint(); } } 三、在Java Applet小程序中使用JavaScript Live Connect提供了Java与JavaScript的接口,可以允许在Java Applet小程序中使用JavaScript。具体步骤如下: 1) 在HTML脚本中使用〈APPLET〉标志的MAYSCRIPT属性,以允许Java Applet小程序访问脚本; 2) 将netscape. JavaScript包导入Java Applet小程序; 3) 在Java Applet小程序中用JSObject类的getWindow( )方法创建JavaScript窗口的句柄; 4) 在Java Applet小程序中用JSObject类的getMember( )方法访问JavaScript对象; 5) 在Java Applet小程序中用JSObject类的eval( )方法调用JavaScript方法。 示例: “ReadForm. Java” import netscape.javascript.JSObject; import netscape.javascript.JSException; //可允许在小程序中处理异常事件 …… win=JSObject.getWindow(this); // 获取JavaScript窗口句柄,引用当前文档窗口 doc=(JSObject)win.getMember("document"); // 访问JavaScript对象 form=(JSObject)doc.getMember("textForm"); textField=(JSObject)form.getMember("textField"); text=(String) textField.getMember("value"); //获取文本区的值 …… win.eval("alert(\"This alert comes from Java!\")"); // 调用JavaScript的alert()方法 …… “User.htm” ……

Enter text and then click display text:

//必须使用MAYSCRIPT属性标志 <

小小豆叮

如何正确地应用Runtime类调用程序

用Java编写应用时,有时需要在程序中调用另一个现成的可执行程序或系统命令,这时可以通过组合使用Java提供的Runtime类和Process类的方法实现。下面是一种比较典型的程序模式: ... Process process = Runtime.getRuntime().exec(".\\p.exe"); process.waitfor( ); ... 在上面的程序中,第一行的“.\\p.exe”是要执行的程序名,Runtime.getRuntime()返回当前应用程序的Runtime对象,该对象的exec()方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。通过Process可以控制该子进程的执行或获取该子进程的信息。第二条语句的目的等待子进程完成再往下执行。 但在windows平台上,如果处理不当,有时并不能得到预期的结果。下面是笔者在实际编程中总结的几种需要注意的情况: 1、执行DOS的内部命令 如果要执行一条DOS内部命令,有两种方法。一种方法是把命令解释器包含在exec()的参数中。例如,执行dir命令,在NT上, 可写成exec("cmd.exe /c dir"),在windows 95/98下,可写成“command.exe /c dir”,其中参数“/c”表示命令执行后关闭Dos立即关闭窗口。另一种方法是,把内部命令放在一个批命令my_dir.bat文件中,在Java程序中写成exec("my_dir.bat")。如果仅仅写成exec("dir"),Java虚拟机则会报运行时错误。前一种方法要保证程序的可移植性,需要在程序中读取运行的操作系统平台,以调用不同的命令解释器。后一种方法则不需要做更多的处理。 2、打开一个不可执行的文件 打开一个不可执行的文件,但该文件存在关联的应用程序,则可以有两种方式。 以打开一个word文档a.doc文件为例,Java中可以有以下两种写法: exec("start .\\a.doc"); exec(" c:\\Program Files\\Microsoft Office\\office\\winword.exe .\\a.doc"); 显然,前一种方法更为简捷方便。 3、执行一个有标准输出的DOS可执行程序 在windows平台上,运行被调用程序的DOS窗口在程序执行完毕后往往并不会自动关闭,从而导致Java应用程序阻塞在waitfor( )。导致该现象的一个可能的原因是,该可执行程序的标准输出比较多,而运行窗口的标准输出缓冲区不够大。解决的办法是,利用Java提供的Process类提供的方法让Java虚拟机截获被调用程序的DOS运行窗口的标准输出,在waitfor()命令之前读出窗口的标准输出缓冲区中的内容。一段典型的程序如下: ... String ls_1; Process process = Runtime.getRuntime().exec("cmd /c dir \\windows"); BufferedReader bufferedReader = new BufferedReader( \ new InputStreamReader(process.getInputStream()); while ( (ls_1=bufferedReader.readLine()) != null) System.out.println(ls_1); <

小小豆叮

在Java中获取系统属性

Java语言以其面向对象、跨平台、可移植性好、安全性高等优点,受到众多编程人员的青睐,越来越多的人将其作为应用软件开发语言的首选。 在Java应用程序运行时,特别是需要在跨平台工作环境下运行时,需要确定操作系统类型、用户JDK版本和用户工作目录等随工作平台变化的信息,来保证程序正确运行。一般情况下,可以利用JDK提供的系统属性类(Properties)中的方法,快速地获取工作环境信息。另外,程序开发人员还可以定义与应用程序相关的系统属性文件,在用户程序执行过程中动态地加载程序员定义的属性文件来控制程序运行。 本文通过对系统属性类的分析,结合实际例子介绍如何定义系统属性文件,并讨论安全策略文件的定义。 属性类 Java Properties类的继承关系如下: java.lang.Object <

小小豆叮

一个java写的聊天室,非常不错

<

小小豆叮

ejb内部资参之三

EJB开发概述 1、EJB的开发 先泛泛而论,讲一讲EJB的开发步骤。 1.1 SessionBean的开发 第一步, 写远程接口(remote interface), 继承EJBObject接口,把需要调用的public方法写在里面(这些方法将在SessionBean中实现),注意要声明throws java.rmi.RemoteException。 例如: package jsper.ejb;     import java.rmi.*; import javax.ejb.*; public interface MyEJB extends EJBObject { public String sayHello() throws java.rmi.RemoteException; } 第二步, 写Home接口(生成EJBObject引用的factory) 至少生成一个create方法, 注意要声明throws java.rmi.RemoteException和javax.ejb.CreateException。 比如:     package jsper.ejb; import java.rmi.*; import javax.ejb.*;   public interface MyEJBHome extends EJBHome {     MyEJB create() throws java.rmi.RemoteException, javax.ejb.CreateException; } 第三步, 写真正的Session Bean的实现(实现定义在远程接口中的方法), 需要实现javax.ejb.SessionBean接口 注意:不能用implents MyEJB的方式直接实现远程接口,此处不用抛出RemoteException package jsper.ejb; import java.rmi.RemoteException; import javax.ejb.*; public class MyEJBClass implements SessionBean {    public MyEJBClass() {  }  //定义在SessionBean 中的方法  public void ejbCreate() throws RemoteException, CreateException {  }  public void ejbActivate() throws RemoteException {  }  public void ejbPassivate() throws RemoteException {  }  public void ejbRemove() throws RemoteException {  } public void setSessionContext(SessionContext ctx) throws RemoteException {  }  //此处是具体的实现  public String sayHello()  {   System.out.println("Hello");  } } 第四步,写一个发布用的配置文件ejb-jar.xml 需要提供的信息: Bean Home name -- The nickname that clients use to lookup your bean's home object. Enterprise bean class name -- The fully qualified name of the enterprise bean class. % ejb内部资参之一 ejb内部资参之二 ejb内部资参之三 ejb内部资参之四 ejb内部资参之五 <

小小豆叮

ejb内部资参之二

使用EJB你就不用你自己写支持分布式的对象的框架了   Java Beans是个功能的部件,而不是一个可运行的程序, 不需要也不能发布它, 但它又必须有一个可依赖的环境来运行 EJB则是可发布的部件、发布到一个容器中, 装配成更大的系统 EJB和Applet和Servlet相似, Applet的容器是Browser, Servlet的容器是 支持Java的Web Server, 而EJB的容器是Application Server EJB1.1  (2.0的规范已经发布了,请到sun去download) 软件生产工业化 多层应用简单化 事务处理 并发安全 Enterprise beans当前两个类型(2.0中有新内容, 我自己还没理解,不多讲了) Session Beans(又包括stateful 和stateless) 业务过程相关的逻辑,比如各种计算,查询 entity beans 数据相关的逻辑, 比如修改帐号的余额 EJB的规范定义了一些你的Bean可以实现标准的接口。 这些接口强迫你实现其中特定方法。EJB的容器使用这些方法来管理你的Bean以及传递事件 最基本的接口javax.ejb.EnterpriseBean public interface javax.ejb.EnterpriseBean extends java.io.Serializable {} 这个接口中没有方法,起到标示你的Bean是个Enterprise bean. sesssion beans 和entity beans有许多接口都是从这个特定的接口继承来的(所以你的bean并不直接实现EnterpriseBean接口)。所有的session beans都从javax.ejb.SessionBean继承,同理所有的EntityBean都从javax.ejb.EntityBean继承。 remote object 由MiddleSoftware提供的工具生成 remote interface 远程接口---客户端的应用调用的接口 java.ejb.EJBObject public interface EJBObject extends java.rmi.Remote { public abstract javax.ejb.EJBHome getEJBHome() throws java.rmi.RemoteException; public abstract javax.ejb.Handle getHandle() throws java.rmi.RemoteException; //一个EJB的持续引用, 存储起来重新构造 public abstract java.lang.Object getPrimaryKey() throws java.rmi.RemoteException; //只用在Entity Beans public abstract boolean isIdentical(javax.ejb.EJBObject param1) throws java.rmi.RemoteException; public abstract void remove() throws java.rmi.RemoteException, javax.ejb.RemoveException; }     home object -- EJB object factory, 由工具生成,是EJB container的一部分 创建EJB objects 发现已经存在的EJB objects (for entity beans) 删除EJB objects home interface --本地接口, 定义创建的方法,查找的方法和析构的方法   package javax.ejb; import java.rmi.Remote; import java.rmi.RemoteException; // Referenced classes of package javax.ejb: //      RemoveException, EJBMetaData, HomeHandle, Handle public interface EJBHome   extends Remote {   public abstract EJBMetaData getEJBMetaData()     throws RemoteException;   public abstract HomeHandle getHomeHandle()     throws RemoteException;   public abstract void remove(Object obj)     throws RemoteException, RemoveException;   public abstract void remove(Handle handle)     throws RemoteException, RemoveException; }   session bean package javax.ejb; import java.rmi.RemoteException; // Referenced classes of package javax.ejb: //      EJBException, EnterpriseBean, SessionContext public interface SessionBean   extends EnterpriseBean {   public abstract void ejbActivate()     throws EJBException, RemoteException;   public abstract void ejbPassivate()     throws EJBException, RemoteException;   public abstract void ejbRemove()     throws EJBException, RemoteException;   public abstract void setSessionContext(SessionContext sessioncontext)     throws EJBException, RemoteException; } setSessionContext(SessionContext sessioncontext) session context 是session bean 和container交互的通道, 通常的实现: import javax.ejb.*; public class MyBean implements SessionBean { private SessionBean sessiontext; public void setSessionContext(SessionContext sessioncontext)      throws EJBException, RemoteException     {      this.sessiontext = sessiontext;     }          ...... }   public void ejbCreate(...) 至少实现一个 home object实现相应参数的一个create方法 比如 你的bean中有一个ejbCreate(int i)时 home object中有 public void create(int i)   钝化和激活 ---仅用于stateful session bean   public abstract void ejbPassivate()   public abstract void ejbActivate()    当太多的session bean被事例化时,container做钝化和激活操作, 释放和打开资源         //stateless session bean 对于所有的客户端是相同的,所有的信息通过参数传递或从数据库等外部得到 初始化的唯一方式是无参数的 ejbCreate()方法 home object 有相应的无参数create()方法   客户端调用过程: 1、Look up a home object. 2、Use the home object to create an EJB object. 3、Call business methods on the EJB object. 4、Remove the EJB object. Look up a home object your client code must use the JNDI. J2EE products exploit directory services to stroe location infromation for resources that your application code uses in an enterprise deployment. These resources could be EJB home objects, enterprise bean enviroment properties, database derivers, message service drivers, and other resources. By using directory services, you can writer application code that does not depend on specific machine names or locations. This is all part of EJB's location transparency, and it keeps your code portable. If later you decide thata resources should be located elsewhere, your code will not need to be rebuilt because the directory service can simply be updated to reflect the new resource locations. This greatly enhances maintenance of a multi-tier deployment that may evolve over time. There are two common steps that must be taken to find any resource in a J2EE deployment: 1. Associate the resource with a "nickname" in your deployment descriptor. Your J2EE product will bind the nickname to the resource. 2. Clients of the resource can use the nickname with JNDI to look up the resource across a deployment. 目前的主要的分布式应用框架 1、 Miscrosoft's Distribute interNet Appplications Architecture(DNA) 相关的平台和技术 NT DCOM MSMQ MTS Microsoft Wolfpack Microsoft SQL Server Microsoft Internet Information Server Microsoft Management Console 2、SUN's J2EE J2EE是规范而不是产品, 不至于让用户绑定到一个卖家(Microsoft) 支持高端的Unix平台 内置的CORBA支持 3、The Object Management Group's CORBA Standard Common Object Request Broker Architecture (CORBA) Internet Inter-ORB Protocol (IIOP) ejb内部资参之一 ejb内部资参之二 ejb内部资参之三 ejb内部资参之四 ejb内部资参之五 <

小小豆叮

Sun的java官方网站

<

小小豆叮

ejb内部资参之一

nterpriseJavaBean 入门 一 基本知识 1. 背景 Java由于其良好的跨平台行而成为服务器端的理想语言,为了利用Java实现服务器端的计算,SUN推出了一个完整的开发平台J2EE,其目的是为基于Java的服务器端配置提供一个独立于平台的可携带的多用户企业级的安全平台,而J2EE的基石就是Enterprise JavaBeans(EJB),EJB是建立基于JAVA的服务器端组件的标准,它定义了如何编写服务器端组件,提供了组件与管理组件的应用服务器之间的标准约定,EJB是一种组件架构,使得开发人员能够快速开发出具有伸缩性的企业级应用。 2. EJB简介 1)JavaBeans和Enterprise JavaBeans JavaBeans是Java的组件模型。在JavaBeans规范中定义了事件和属性等特征。Enterprise JavaBeans也定义了一个Java组件模型,但是Enterprise JavaBeans组件模型和JavaBeans组件模型是不同的。 JavaBeans重点是允许开发者在开发工具中可视化的操纵组件。JavaBeans规范详细地解释了组件间事件登记、传递、识别和属性使用、定制和持久化的应用编程接口和语意。 Enterprise JavaBeans的侧重点是详细地定义了一个可以portably地部署Java组件的服务框架模型。因此,其中并没提及事件,因为enterprise bean通常不发送和接受事件。同样也没有提及属性------属性定制并不是在开发时进行,而是在运行时(实际上在部署时)通过一个部署描述符来描述。 不要寻找JavaBeans和Enterprise JavaBeans之间的相似性。他们都是组件模型规范,但是前者说明了开发工具中应用程序组装的问题,而后者则侧重于部署组件的服务框架的细节。不要错误地认为JavaBeans是用于客户端的开发,Enterprise JavaBeans是用于服务器端的开发。JavaBeans也可作为进行非图形化服务器端Java应用开发的组件模型。区别是当你使用JavaBeans创建服务器应用时,你还得设计整个的服务框架。用Enterprise Javabeans框架是现成的,你只需遵守它的APIs.对于复杂的服务器端应用程序,显然使用Enterprise JavaBeans比重新开发更简单 2)EJB体系结构 EJB是一种组件架构,它采用分而制之的方法实现服务器端的计算。 EJB规范定义了六种不同的角色来完成其任务, 包括: ? Bean provider: 提供可重用的商业组件 ? Container provider: 为ejb 应用提供低层次的运行环境 ? Server provider:提供应用程序服务器用以包含,管理和配置ejb组件,目前EJB规范没有提供EJB Container和EJB Server之间的接口,故二者的提供商是合一的,有:BEA的Weblogic server,SUN的NetDynamics,IBM的WebSphere,Oracle的8i等。 ? Application assembler:负责将不同的组件组织起来构成能够运行的应用程序 ? Deployer: 负责将要使用的组件安装到应用服务器中并加以配置 ? System Administrator: 负责配置好的系统的管理等 这六种角色的流程图如下: Enterprise JavaBean 驻留在EJB Container中,通过EJB Container对ejb进行管理。EJB规范定义了二者之间的接口。 Javax.ejb.EJBHome接口列出了所有定位、创建、删除EJB 类实例的方法。Home对象是home接口的实现。EJB类开发者必须定义home接口。EJB Container Provider应该提供从home接口中产生home对象实现的方法。 远程接口(remote interface)列出了EJB类中的商业方法。Javax.ejb.EJBObject实现远程接口,并且客户端通过它访问EJB实例的商业方法。EJB开发者定义远程接口,EJB Container Provider提供产生相应的EJBObject的方法。客户端不能得到EJB实例的引用,只能得到它的EJBObject实例的引用。当客户端调用一个方法,EJBObject接受请求并把它传给EJB实例,同时提供进程中必要的包装功能。客户端应用程序通过home对象来定位、创建、删除EJB类的实例,通过EJBObject来调用实例中的商业方法。客户端可以用Java来编程,通过Java RMI来访问访问home对象和EJBObject,或用其他语言编程并通过CORBA/IIOP访问,使得部署的服务器端组件可以通过CORBA接口来访问。 Enterprise javaBean规范将Enterprise Beans 分为两种:session bean和entity bean. I. session bean表示的是调用它的客户端代码索要完成的工作,是一种商业处理过程对象,它实现商业逻辑,商业规则以及工作流程,例如:报价,订单处理,视频压缩,股票交易等。session bean之所以叫session bean是因为其生命周期与调用它的客户端相同。 session bean又分为两种:stateless和stateful, stateful session bean用于贯穿多个方法请求和事务的商业过程,例如:网上商店,用户进入商店后,可以将商品加入再现的购物车,组件必须跟踪用户的状态(如:购物车);而stateless session bean用于客户调用方法期间不用维护任何状态信息,例如:解决复杂数学运算的视频压缩/解压缩。 II. entity bean用来代表商业过程中处理的永久性的数据,例如:银行出纳员组件完成储蓄等商业过程,其中涉及的数据时银行账户数据 entity bean用来代表底层的对象。最常用的是用entity bean代表关系库中的数据。一个简单的entity bean 可以定义成代表数据库表的一个记录,也就是每一个实例代表一个特殊的记录。更复杂的entity bean可以代表数据库表间关联视图。在entity bean中还可以考虑包含厂商的增强功能,如对象--关系映射的集成。 通常用entity类代表一个数据库表比代表多个相关联的表更简单且更有效。反过来可以轻易地向entity类的定义中增加关联,这样可以最大地复用cache并减小旧数据的表现。 III. entity bean和session bean的比较 看起来session bean好象没什么用处,尤其对于数据驱动的应用程序。当然事实并不是这样。因为entity bean(譬如说)代表底层数据库的一行,则entity bean实例和数据库记录间就是一对一的关系。因为多个客户端必须访问底层记录,这意味着,不同于session bean,客户端必须共享entity bean。因为是共享的,所以entity bean不允许保存每个客户端的信息。session bean允许保存客户端的状态信息,客户端和session bean实例间是一对一的。entity bean允许保存记录的信息,entity bean实例和记录间是一对一的。一个理想的情况是客户端通过session bean连接服务器,然后session bean通过entity bean访问数据库。这使得既可以保存客户端的信息又可以保存数据库记录的信息。  同时session bean也不能提供在相同或不同的EJB类调用间进行全局的事务控制。没有session bean,应用程序开发者(客户端开发者)就必须理解EJB类的事务要求,并使用客户端的事务划分来提供事务控制。EJB的主要好处就是应用开发者不需知道EJB类的事务需求。一个session bean可以代表一个商业操作,进行事务控制,不需要客户端进行事务划分。 以下我们作为EJB provider的角色来讨论Enterprise javaBean的开发。 3,EJB 开发 A) Enterprise JavaBean的由如下部分构成 Enterprise Bean 类: 包含ejb 组件的详细实现,对于session Bean它代表了 与业务处理相关的逻辑的实现,而对于entity Bean 它代表了与数据逻辑相关的实现 EJB Object :是由EJB Container来实现的远程接口,它是客户端和bean 实例之间的中介,传递客户端调用到bean 实例; Home 接口:充当EJB Object工厂的java接口,创建EJB Object,Home接口的实现由EJB Container负责。 Deploy descriptor:描述你的ejb 中间件的相关要求,包括:通知EJB Container如何管理你的bean,事务的需要,安全需要等等。 特定于bean 的属性: 利用该属性,bean可以在运行时读取并调整自己的功能 Ejb-jar 文件:将生成的bean 类,home接口,Ejb object,deployment descriptor和bean 的properties 打包进ejb jar 文件,这样就可以deploy了。 B) Enterprise JavaBean编程的具体步骤 实现javax.ejb.EnterpriseBean接口: 对于session bean 可以直接实现javax.ejb.SessionBean接口,对于entity bean 可以直接实现javax.ejb.EntityBean接口,而后实现本bean特有的功能。 扩展javax.ejb.EJBObject接口: 增加在Enterprise Bean实现类中供客户调用的方法的相应的方法,必须相同 扩展javax.ejb.EJBHome接口: 增加创建上述扩展的javax.ejb.EJBObject接口的相应的create()方法。 编写deploy descriptor文件: 目前EJB 1.1规范规定了用XML文件来描述它,并提供了相应的DTD. 生成EJB jar 文件: 利用jar命令将上述生成的相应文件进行打包。   在第二部分给出了ejb开发的详细说明及相关注意事项 二 例子程序 以下的例子程序是以weblogic server(ver5.1)作为EJB Server(EJB Container)的, 不同的EJB Server 在一些方面有所不同 (不同的地方另加注释) 例子一. Hello, world (Stateless Session Bean) 包括EJB相应接口的扩展和实现、deploy descriptor文件的生成以及.jar文件生成; 服务器端EJB开发 EJB相应接口的扩展和实现:(与EJB Server无关) 第一步: 实现javax.ejb.SessionBean 接口,并提供该Bean的特定功能, "Hello, world" Stateless SessionBean 仅仅向客户端返回“Hello,world!”字符串 注意:除了要实现javax.ejb.SessionBean接口外(ejbActivate(),ejbPassivate(), ejbRemove(), setSessionContext()),必须: 1).实现公共方法ejbCreate(),该方法对于stateless SessionBean 无需带任何参数而对stateful SessionBean则根据需要自定; 2)提供给客户调用的方法, 如:本例的hello()方法 package com.jsper.ejbexample.session.helloworld; import javax.ejb.*; import java.rmi.RemoteException; public class HelloBean implements SessionBean { public HelloBean() { super(); } /** *由EJB Server(EJB Container) 调用,用于激活SessionBean的实例 */ public void ejbActivate() throws EJBException, java.rmi.RemoteException { System.out.println("ejbActivate()"); } /** *由EJB Server(EJB Container) 调用,用于创建本SessionBean的实例 * 创建日期:(2000-8-1 16:00:45) */ public void ejbCreate() throws javax.ejb.CreateException { System.out.println("ejbCreate()"); } /** * 由EJB Server(EJB Container) 调用,用于惰化SessionBean的实例 */ public void ejbPassivate() throws EJBException, java.rmi.RemoteException { System.out.println("ejbPassivate()"); } /** * 由EJB Server(EJB Container) 调用,用于删除SessionBean的实例 */ public void ejbRemove() throws EJBException, java.rmi.RemoteException { System.out.println("ejbRemove()"); } /** * 本SessionBean提供给客户调用的方法,但不能由客户直接调用,而是通过EjbObject远程接口调用 * 创建日期:(2000-8-1 16:04:58) * @return java.lang.String */ public String hello() { return "Hello, World!"; } /** * 由EJB Server(EJB Container) 调用,用于设置SessionBean的上下文 */ public void setSessionContext(SessionContext arg1) throws EJBException, java.rmi.RemoteException { System.out.println("setSessionContext()"); } } 第二步:扩展javax.ejb.EJBObject接口,增加在第一步SessionBean 接口实现中提供给客户调用 的方法, 如本例的hello()方法 注意:1)增加的方法名称必须与相应的SessionBean实现中方法相同(case-sensitive); 2) 增加的方法必须抛出java.rmi.RemoteException异常 package com.jsper.ejbexample.session.helloworld; import java.rmi.*; import javax.ejb.*; public interface Hello extends EJBObject { /** * 由客户端直接调用,返回“hello,world!”,实现由相应的SessionBean完成 * 创建日期:(2000-8-1 15:56:25) * @return java.lang.String * @exception java.rmi.RemoteException 异常说明。 */ String hello() throws java.rmi.RemoteException; } 第三步:扩展javax.ejb.EJBHome接口,增加创建EJBHome接口对象的create()方法 注意: 1)create()方法中参数的有无无关紧要,但必须与SessionBean接口实现类中ejbCreate()方法相对应,包括从方法的个数上和参数上;例如:若SessionBean接口实现类中有ejbCreate(),ejbCreate(int nVal)方法,则该接口扩展中必须增加create(),create(int nVal)方法 2)create()方法必须抛出javax.ejb.CreateException 和java.rmi.RemoteException 异常 package com.jsper.ejbexample.session.helloworld; import java.rmi.*; import javax.ejb.*; public interface HelloHome extends EJBHome { /** * 创建EJBObject扩展对象Hello * 创建日期:(2000-8-1 16:13:53) * @return com.jsper.ejbexample.session.helloworld.Hello * @exception javax.ejb.CreateException 异常说明。 * @exception java.rmi.RemoteException 异常说明。 */ Hello create() throws javax.ejb.CreateException, java.rmi.RemoteException; } ? deploy descriptor文件的生成 EJB1.1规范规定了必须利用xml文件构造deploy descriptor文件,并给出了相应的DTD。本例的ejb-jar.xml文件如下: images/green-cube.gif        images/orange-cube.gif helloworld com.jsper.ejbexample.session.helloworld.HelloHome com.jsper.ejbexample.session.helloworld.Hello com.jsper.ejbexample.session.helloworld.HelloBean Stateless Container  BEAS  java.lang.Double  100.0  MSFT  java.lang.Double  150.0                helloworld  Remote  * Required          对于weblogic Server还必须构造一个名为weblogic-ejb-jar.xml的文件,BEA公司给出了相应的DTD.它描述了相应的EJB的名称以及JNDI的名称(**该部分与EJB Server有关,ejb开发人员可省去,而由DEPLOYER来完成**)       helloworld     100        hello.HelloHome      ? 提供用于标示本EJB的大小图标(icon),注意:图像的格式必须是JPEG 或 GIF。 本例提供了图像文件:orange-cube.gif和green-cube.gif(见附件) ? 构造.jar文件 第一步:编译相应的.java文件 本例中包括:Hello.java,HelloBean.java,HelloHome.java ,位于包com.jsper.ejbexample.session.helloworld中。编译后相应的.class文件放在相对目录com\jsper\ejbexample\session\helloworld 中。 第二步:创建与com的同级目录META-INF,将相应的.xml文件拷贝到该目录下;将相应的图标文件拷贝到相对目录(相对于该.xml文件父目录)中(本例为与com的同级目录images) 第三步:利用JAR命令将目录com,images,META-INF中的内容做成.jar文件 本例JAR文件名成为std_hello.jar jar cv0f std_hello.jar META-INF com images 至此, 对于EJB Provider的工作已经完成。 但是由于我们的开发人员在开发ejb的时候需要进行本地调试等工作,因此其既充当ejb provider的角色,又充当其他的脚色, 因此,其可能需要作如下工作(仅供参考,接上述工作): ? 生成可deployable的jar文件 前边生成的jar文件(若不含weblogic-ejb-jar.xml文件)是不依赖于ejb server(ejb container)的,而如前所述,不同的ejb server对于ejb的配置是不同的,因此需要加上特定的信息 对于weblogic server则是通过相应的ejbc命令或deploy utility在原.jar文件的基础上生成新的可deployable的.jar文件。(关于ejbc的详细使用请参见有关资料): java ?classpath e:\weblogic\classes;e:\weblogic\lib\weblogicaux.jar -Dweblogic.home=e:\weblogic weblogic.ejbc -compiler javac std_hello.jar ejb_helloworld.jar ? 设定weblogic的环境 将最终的jar文件(本例ejb_helloworld.jar)放在weblogic的某一子目录下(例如:myserver),而后将.jar文件所在的路径( e:/weblogic/myserver/ ejb_helloworld.jar)添加到weblogic.properties文件的入口weblogic.ejb.deploy中(weblogic.ejb.deploy=e:/weblogic/myserver/ejb_helloworld.jar) ? 启动weblogic server, 在其启动的控制台中可以见到相应的ejb的装载成功的信息。   ? 客户端调用 当EJB装载成功后,就可以通过客户端对其进行调用,以进行测试或运行 客户端调用比较简单,但与EJB Server有很大关系,主要体现在利用JNDI服务搜寻相应的EJBHome 接口对象上。 1. 编写.java 文件 主要包括:利用相关属性初始化运行的Context;搜寻EJBHome接口;利用EJBHome接口创建EJBObject接口对象;利用EJBObject接口对象调用有关的方法。 注意: 1) 远程访问ejb与本地访问ejb有所不同,不同之处在于获取Bean的InitialContext的方法。 远程访问ejb可以通过如下的getInitialContext()方法。 本地客户(如servlet等)访问只需简单的利用InitialContext的却省构造函数即可 Context ctx = new InitialContext(); 2)客户端可以通过如下四个不同的协议之一同weblogic server 连接:T3,T3S. HTTP,HTTPS 但是却省端口不同: T3,HTTP---7001;T3S,HTTPS----7002,而且最好使用T3协议(详细情况请参见文档weblogic\classdocs\API_client.html) 3)必须导入EJB提供的客户端接口(即接口EJBHome和EJBObject的扩展),如本例的 import com.jsper.ejbexample.session.helloworld.*   import com.jsper.ejbexample.session.helloworld.*; import java.rmi.*; import javax.rmi.*; import java.util.*; import javax.ejb.*; import javax.naming.*; public class HelloClient extends Object {   public static void main(String[] args) {   try {  // Get an InitialContext  String url="t3://localhost:7001";  Context ctx = getInitialContext(url,null,null);  //look up EJBHome interface object  HelloHome home = (HelloHome)ctx.lookup("hello.HelloHome");  //create the EJBObject interface object  Hello hello = home.create();    //call the corresponding method in EJB  System.out.println(hello.hello());  hello.remove(); } catch(Exception e) { e.printStackTrace(); }  } /**   * Using a Properties object will work on JDK 1.1.x and Java2   * clients   */  static Context getInitialContext(String url, String user, String password ) throws NamingException { try {  // Get an InitialContext  Properties h = new Propertie   ejb内部资参之一 ejb内部资参之二 ejb内部资参之三 ejb内部资参之四 ejb内部资参之五 <

小小豆叮

一个可以查看世界时区时间的applet

<

小小豆叮

ejb内部资参之四

EJB Context, 你和EJB Container交换信息的通道 Home Object和EJB Object的信息 transaction 安全信息 环境的属性   EJB中EJB Object 可以是别的Beans的client端,这样当你需要call 别的bean和传引用给自己的bean 时,不能用this关键字, 而应该用SessionContext.getEJBObject()方法 EJB的安全机制 第一步、 client端必须被验证。 证实他是本EJB的用户。也许需要输入username/password。 一般的中间件产品都能和成熟的目录服务集成。 当然也有很简单粗糙的做法,比如weblogic就有一种: weblogic.password.employeeA=passwordA   第二步、必须被批准有相应的权限做相应的操作 两种方式:一种是叫declarstive authorization. 由Container去代理一切。 只是在deploy时给相应的角色分配权限。 weblogic.security.group.emplyees=employeeA weblogic.security.group.manager=employeeB weblogic.security.group.administrators=AdminA 另一种自己在程序中去验证   ejb内部资参之一 ejb内部资参之二 ejb内部资参之三 ejb内部资参之四 ejb内部资参之五 <

小小豆叮

ejb内部资参之五

这里讲讲如何使用jdeveloper开发EJB。在此之前请先阅读 ‘EJB开发概述.doc' 由于jDeveloper中提供了一系列的向导(写起文档很麻烦)完成各种功能,兼之jDeveloper中的帮助说明得很详细,没有另写文档 jDeveloper的文档在 Help->help topics->user's guaides->Developing Applications->Developing Java Components->Developing and Deploying Enterprise JavaBeans 使用jDeveloper3.0能够开发EJB1.0(可惜不支持EJB1.1), 并能把EJB发布到Oracle8i(需要配置成多线/进程服务器)或Oracle Application server/iAs 开发EJB的方式: 通过向导file->new...->Enterprise java bean 1、生成一个新的EJB类框架和Remote interface, Home interface 2、把已经存在的类封装成EJB 3、把已经存在的EJB的class文件封装成EJB 注意: 根据jdeveloper提供的这些功能,我们可以省去写Remote interface 和Home interface的工作。 而直接写EJB 实现文件甚至bean文件, 但为了使开发的东西看起来干净一些,建议不要使用包装bean的方式。 生成Deployment descriptor文件, jDevelper提供一个向导做这件事情, 挺简单的 在生成EJB的向导中选择可以生成Deplyment descriptor文件, 以后双击生成的.prf文件向Oracle8i或OAS发布。 或者: 在项目文件夹右击鼠标->New Deployment Profile... 或者: 在EJB文件夹右击鼠标->Create jServer/EJB deployment profile...或create OAS/EJB deployment profile... 以后就是按照向导的提示一步步进行,不再赘述。   使用jDeveloper开发EJB的总体印象: 优点: 由于是和自己的产品(8i/OAS)整合在一起, jDeveloper开发EJB是一个好的思路, 速度是很快的(不出错的情况下), 隐藏了Deploy的大部分细节,大大加快开发进度。根据。 缺点: 1、8i只支持EJB的1.0规范, 版本有点低。(根据Oracle公司的iAS 白皮书, iAS的版本2支持EJB1.1)。 而别的产品如weblogic, jrun现在支持的时EJB1.1规范,这样在向这些平台发布时还有一定的工作量。(1.0中deploy descriper是java类, 在1.1中已改为ejb-jar.xml文件) 3、在8i中没有和servlet和jsp的引擎在本地,这样在web server访问EJB时实际上是从外部, JNDI访问需要先验证身份, 给客户端servlet程序的移植带来一定的工作量(OAS没有这个问题)。 2、在有的机器上jDeveloper3.0的connection manager有时连接8i不能成功, 开发无法进行。具体原因尚未查明。(在程序中能连接成功) 3、在向8i deploy时出错时定位错误困难, 提示往往只是complie failed或deploy failed给开发造成困难。 4、稳定性欠佳。较频繁地出现非法访问内存之类的错误   根据以上原因, 可以考虑使用支持EJB1.1规范的iAS作为将来程序开发的平台。在别的平台做实施只需用相应平台的Deploy tools重新发布EJB. ejb内部资参之一 ejb内部资参之二 ejb内部资参之三 ejb内部资参之四 ejb内部资参之五 <

小小豆叮

一个关于java FAQ的站点

<

小小豆叮

一个比较全的搭建java环境的英文下载网站

<

小小豆叮

Enterprise JavaBeans导论二

理解EJB组件 你现在应该已经熟悉了整个EJB体系结构及其主要的部件。这一节更详细地描述了这些部件,并解释它们运行时的行为语意。 Home接口 EJB库使用enterprise bean的客户端通过它的home接口创建它的实例。Home接口包含一个或多个用来创建enterprise bean实例的create()方法。这个home接口不是由bean来实现,而是通过称为home object的类来实现。一个home object的实例在服务器中实例化,使得客户端可以访问它们。 定位home object 一个home object的引用被放在名字服务中,客户端能通过JNDI访问它。EJB服务器一般提供某种名字空间的实现,虽然有时可以使用外部的名字空间。在这两种情况下客户端都必须知道名字空间的位置以及JNDI的上下文类。例如,一个客户端的applet可能接收名字空间和JNDI上下文类作为applet的参数。 除了提供位置和类名,客户端也必须知道在名字树中定位home object.这些必须在客户端启动时提供。当部署者把enterprise bean部署进EJB服务器中时,他必须可以以参数形式指定名字树,如ejb/accounting/AccountsPayable.客户端必须获得这个完整的路径名来定位并获得AccountsPayable home object的引用。并不是说客户端通过JNDI获得容器。客户端使用JNDI查找home接口的实现。Home接口的实现由某个特殊的container来提供,但这是该容器厂商的细节,enterprise bean开发者和客户端应该忽略它。 Home接口中的方法 Enterprise bean开发者定义ejbCreate()方法的同时必须在home接口中声明与其相应的create()方法。实体bean可以包含finder方法以使得客户端能定位已有的实体bean. Home接口是通过继承javax.ejb.EJBHome来定义的。该接口包含如下的方法: public interface javax.ejb.EJBHome extends Remote { public EJBMetaData getEJBMetaData() throws RemoteException; public void remove(Handle handle) throws RemoteException,RemoveException; public void remove(Object primaryKey) throws RemoteException,RemoveException; 一个bean的home接口可以象下面这样: public interface myHome extends EJBHome { public myRem create() throws RemoteException,CreateException; public myRem create(String str) throws RemoteException,CreateException; 其中 public interface myRem extends EJBObject { … } 容器开发商负责提供实现home接口的home对象,因为只有开发商才能实现存贮enterprise bean的库的编码。 容器 定义容器在理解EJB规范时容器这个术语并不应从字面上简单地理解为类,而是一层代替bean执行相应服务的接口。容器开发商提供运行在EJB服务器中一套完成这些功能的工具和接口。 这些服务包括: ·与二级存储中交换(对会话bean) ·持久性管理(对实体bean) ·实现创建和查找服务的home object的可用性 ·在可通过JNDI访问的名字空间home object的可视性 ·正确的创建、初始化和删除bean ·保证商业方法正确地运行在事务上下文中 ·实现某一基本的安全服务 ·从home object和EJBObject上的RMI上产生stub和skeleton 容器和EJBObject对规范经常引用由容器或EJBObject提供的服务。这些服务只是用来说明而不暗示特殊类的服务需求。支持enterprise bean的EJBObject和容器类都由容器开发商提供。这些类必须完成bean容器的功能。对bean来说容器和EJBObject是不同的入口点,对某个特殊的服务提供支持独特的能力。例如,容器通过读部署描述符来知道应用于bean方法的事务属性。然而,这些商业方法通过EJBObject调用。 EJBObject必须与容器通讯来确定调用商业方法的事务上下文。确定以后,EJBObject在调用商业方法以前建立事务上下文。重要的是EJBObject 和容器的协同工作来实现容器所需的事务。容器厂商提供二者的实现,但对二者的功能分割却是自由的。与home接口的关系 目前厂商提供工具来读home 接口并产生作为容器的home object.在这种情况下厂商对每个enterprise bean类使用不同的容器类。容器厂商可以使用其它的实现策略,如一个容器类实现多个home接口,甚至一个标准的容器类创建独立的home object实现。唯一的必要条件是容器厂商必须使客户端能通过JNDI访问home object. 客户端和bean开发者都不需关心容器和home object的实现细节。 Enterprise JavaBean Enterprise bean是开发者编写的提供应用程序功能的类。开发者可以选择创建会话bean或实体bean,通过实现不同的接口声明其部署描述符来加以区分。 对于会话bean: public class myBean implements javax.ejb.SessionBean … 对于实体bean: public class myBean implements javax.ejb.EntityBean … 客户端不会直接访问enterprise bean中的任何方法。客户端通过EJBObject 间接调用bean中的方法,EJBObject就象一个代理一样。在把调用通过EJBObject传递时,容器开发商通过包装编码插入其自己的功能,这称为方法插入。方法插入的一个例子是为每个方法调用创建一个新的事务上下文,当方法返回到EJBObject时提交或回滚事务。 当容器厂商的工具在安装bean产生stub和skeleton时,它产生bean的EJBObject一个stub和skeleton.实际上它并不创建bean本身的stub和skeleton,因为bean不会通过网络被访问。EJBObject是真正的网络对象。Bean 是包含应用相关的商业编码的代表。 容器也可以调用bean中的某个方法。例如,容器保证当一个bean 实例生成后,home object中的create()的任何参数会传递bean相应的ejbCreate()方法。 Enterprise bean还有其它的接口和要求。然而,会话bean和实体bean的要求是不同的。这些在随后详述会话和实体bean的章节中会cover. Remote Interface 编写完enterprise bean后开发者创建了一个客户端可访问创建方法的home interface,在home interface中每一个create()方法在相应的bean中都必须有一个ejbcreate()方法。同样,开发者必须创建描述客户端能够访问的商业方法的remote interface。 因为所有的客户端调用都通过EJBObject,因此实现这个接口的是EJBObject而不是home object. Remote interface中列出的方法名和signature必须和实现bean的方法名和signature相同。这不同于home interface--方法signature是一样的,而名字却不同。以下是一个remote interface的例子: public interface Account extends javax.ejb.EJBObject { public void deposit(double amount) throws RemoteException; public void withdraw(double amount) throws RemoteException; public double balance() throws RemoteException; } 所有声明的方法都必须抛出一个RemoteException例外,因为规范要求客户端stub是RMI兼容的。但这并不意味着排除了用其它的传输方式的stub/skeleton实现,如CORBA/IIOP. Remote interface继承javax.ejb.EJBObject接口,增加了额外的方法要求。 EJBObject EJBObject是网络上可视的对象,包含stub和skeleton,作为bean的代理。Bean的remote interface继承了EJBObject接口,而EJBObject类实现这个remote interface,使得bean类有自己的EJBObject类。对每个bean类有一个定制的EJBObject类。 如下是EJBObject接口的定义,被bean的remote interface继承: public interface javax.ejb.EJBObject extends java.rmi.Remote { public EJBHome getEJBHome() throws RemoteException; public Object getPrimaryKey() throws RemoteException; public Handle getHandle() throws RemoteException; public void remove() throws RemoteException,RemoveException; public boolean isIdentical(EJBObject other) throws RemoteException; } 实现这个接口的EJBObject类是一个RMI服务器对象,因为它是他实现了一个RMI remote interface.注意bean本身不是一个remote object,在网络上是不可视的。当容器实例化了这个EJBObject类时,容器会初始化bean实例的引用,使得它能正确地delegate商业方法调用。 厂商的实现是维护EJBObject实例和bean实例的一对一关系。因为remote interface包含EJBObject接口的方法,所以bean不必显式地实现这个接口,虽然它提供了列出的商业方法的实现。因为EJBObject必须正式地实现bean的remote interface,容器在bean安装时产生EJBObject的源代码,这些产生的源代码实现了bean的remote interface.典型的EJBObject有一个独特的类名,作为EJBObject类和bean的联系。 Enterprise JavaBeans导论一 Enterprise JavaBeans导论二 Enterprise JavaBeans导论三 Enterprise JavaBeans导论四 Enterprise JavaBeans导论五 Enterprise JavaBeans导论六 Enterprise JavaBeans导论七 <

小小豆叮

数字时钟(代码)

<

小小豆叮

Enterprise JavaBeans导论七

自管理的事务 如果声明一个bean的事务控制为TX_BEAN_MANAGED,则这个bean可以访问事务服务。当事务控制应用于单个的方法时这个控制只能应用于整个的bean. bean访问事务服务的能力不能只对某个方法起作用。 因此一个方法声明事务控制为TX_BEAN_MANAGED,而另一个方法声明为其它不同的事务控制是错误的。厂商的安装工具应该能检测到并报告这个错误。 Bean分别通过初始化时setSessionContext()或setEntityContext()方法的参数SessionContext或EntityContext来访问事务服务。这些接口都是EJBContext的子类。EJBContext的定义如下: Public interface javax.ejb.EJBContext { public Identity getCallerIdentity(); public boolean isCallerInRole(Identity other); public EJBHome getEJBHome(); public Properties getEnvironment(); public UserTransaction getUserTransaction() throwsIllegalStateException; public boolean getRollbackOnly(); public void set RollbackOnly(); } 一旦bean获得了一个UserTransaction的引用,就可以用这个引用管理自己的事务。 有状态的会话bean的方法可以创建一个事务,而且不用终止事务就可以返回。如果还有线程调用bean的方法,容器检测是否有bean创建的活动的事务,如果被调用的事务是同一个事务,容器会允许该线程重新进入这个bean.如果bean在事务中且执行不同事务上下文的线程试图进入bean,容器会阻塞这个线程直到bean的事务终止。如果线程试图进入事务时bean不在事务中,线程会执行一个自己的事务,容器会挂起线程当前的事务以允许线程进入。一旦线程离开方法就会恢复线程以前的事务,容器不会终止任何方法创建的事务。 对于无状态会话bean和实体bean,当事务活动时bean的方法不允许返回。容器会为此抛出一个例外。 Leaving a tranaction active across method calls is stateful,and is not allowed for stateless session beans.Fro similar reasons,entity beans are also not allowed to maintain an open transaction state across method calls when the bean has declared the TX_BEAN_MANAGED transaction control. 会话同步接口 有状态和无状态的会话bean都可以访问数据库,并且参与一个事务。为了让bean在事务中执行它的任务,bean开发者可以实现在bean中实现javax.ejb.SessionSynchronization接口。容器能自动检测这个接口,容器会使用这个接口中的方法以使bean得到事务的状态信息。实体bean不支持这个接口。因为实体bean are implicitly transaction aware,所以容器使用不同的方法控制一个事务中的实体bean. SessionSynchronization接口定义如下: public interface javax.ejb.SessionSynchronization { public void afterBegin() throws RemoteException; public void beforeCompletion() throws RemoteException; public void afterCompletion(boolean yn) throws RemoteException; } 实际上一个事务不属于一个特殊的bean的实例。一个客户端或容器中执行的线程创建一个事务,在执行bean中的代码时执行该事务。如果一个有事务上下文的线程将要进入一个会话bean,容器首先调用它的afterBegin()方法。Bean可以记录所有的商业方法运行在事务中,随后执行事务操作。如果一个操作的内部标志显示这个线程在事务外运行,则会拒绝执行事务操作的请求。直到调用afterCompletion()方法,bean会继续认为商业方法的调用都在事务中执行。Bean将推断性地清除内部标志,以表示随后到来的事务请求将被拒绝。 如果一个事务上下文的线程试图进入一个已经是另一个事务的一部分的Bean时,.Container将封锁入口,直到前一个事务提交或回滚,并且afterCompletion()方法被调用,此时,允许Bean 恢复它的状态。Container负责提供这些行为。当Container发现它将要提交一个事务时,将在这个事务的所有的session Bean上调用beforeCompletion()方法。这就给Bean足够的机会来结束事务的操作,如在提交前将数据写入数据库。反之,当Container 发现,将要回滚一个事务撕,BeforeCompletion()方法将不会被调用,因为将一个将被回滚的事务所产生的数据写入数据库是没有意义的。 AfterCompletion()是在一个事务即将提交或回滚时被调用,来通知Bean事务操作的最终结果。Bean可以用这个信息来修正自己的内部状态,但它不能用这个信息来维持任何它将要保存的事务。尽管session Bean可以创建,提交和回滚它自己的事务,但通常不推荐这样做。SessionSynchronization接口不提供整合外部和内部事务的能力。如果一个session bean实现了这个接口,则意味着它在方法调用之间要保持事务的状态。特别地,这也暗示在afterBegin()和afterCompletion()调用之间bean是处于一个事务中。这样,如果一个bean实现了SessionSynchronization接口并且在装配符中声明是无状态的就是一个错误。厂商提供的安装工具应该可以捕捉到并报告这个错误。 无状态的session bean可以加入一个事务,但它们不能实现这个接口。事务可以是TX_BEAN_MANAGED,或者container可以在方法入口和从方法的返回上来开始和提交这个事务。Container不可允许在一个现存的事务中有一个线程进入方法,因为无状态的Bean的方法将无法知道正在运行的线程是否正在一个事务中。 解决这个问题的一个方法是使container挂起现存的事务,强迫方法总是认为线程没有在一个事务性的上下文中运行。有状态的Bran可以不实现这个接口而介入事务。但是,装配符必须要认真地配置以使得商务方法总能在正确的事务状态中运行。Bean自己没有通过这个接口来获得自己的事务的状态的权利。 加入事务 EJBContext接口在前面的一节中已经介绍了。其中有两个方法: public boolean getRollbackOnly(); public void setRoolbackOnly(); 这些方法可以有任何bean来使用,而不仅仅是那些声明了其事务控制为bean-managed的bean。事实上,那些处理自己的事务的bean将不会用到这些方法,因为这些方法不是用来和外界的事务管理器进行交流事务状态的。 当一个bean调用了setRollBackOnly()方法时,它是在向事务管理器询问何时结束将要回滚的当前事务。它将给它所参与的事务的结果一个选票。这些方法还存在于UserTransaction接口中,但由于大多数的bean都不访问这个接口,这些方法必须直接地在EJBContext中提供给bean。注意这个方法并不引发回滚操作,它只是简单地设置标志,表示事务在结束时应该回滚。 不象JavaBan属性设置方法,这个方法不以boolean值作为参数。这个方法是特意设计成这样,以使得一个bean不能够改变另一个bean的回滚请求。 一个bean也许希望使用getRoolBackOnly()方法,来检查当前的事务的状态。如果另一个bean已经标志这个事务为rollback,则正在调用的bean可以推测到并决定不能执行那些在、强制性达到操作,如数据库更新,而这些操作很有可能在事务结束时被反转过来。 客户划分的事务 尽管一个JEB厂商所必须的,大服务器厂商也许决定提供一个类,使得用户可以直接访问事务管理器。当需要在同一个上下文中在两个不同的服务器上调用bean时,用户也许会希望这样做。当然,每个bean的装配符可以允许这样的行为。用户可以创建一个事务,然后在两个不同server上的两个不同的bean上调用商务方法,而将事务的上下文也作为调用的一部分进行传递。一旦调用结束,用户将推测地结束事务。有container厂商产生的stub和skeleton将支持事务上下文的隐式传递。 这里是一个可能的例子: Current current = new Current(); Current.setServiceProvider(txMgrURL); Current.create(); Current.begin(); Current.doSomeWork(); RemRef1.doSomeWork(); RemRef2.doMoreWork(); Current.commit(); 数据库操作的事务管理 bean当然希望使用JDBC来建立到数据库的连接,并在其上进行操作。但是,为了符合EJB这种container管理事务的模式,连接不能使用自动提交特性,并且不应该在连接上试图提交或回滚。 Container的角色是决定在这个事务中执行的所有行为应该提交还是回滚。这里提这样一个问题很好:container如何看到并管理由bean方法内部创建的数据库连接。尽管在规范中没有明确地提到,EJB将只能使用JDBC驱动,而JDBC也正是用来和EJB配合使用的。在数据库连接的创建时,驱动程序透明地将连接注册到正在执行的线程的当前事务中。之后当container决定结束事务时,数据库连接将自动地结束它。 用OTS的术语说,数据库连接是不可恢复的资源,有事务服务在container的协助下,隐式地管理。尽管可以在这种情况下使用非事务感知的JDBC Driver,但开发者必须清楚任何在数据库连接上所做的操作都不属于bean的事务,开发者还必须确保在从方法返回之前结束数据库连接事务。试图使用SessionSynchronization接口来合并数据库连接事务和bean本身的事务是不可靠的,是不应该作的。 分布事务的支持 一个分布事务在下面的情况下是需要的: . 一个用户使用用户划分的在多个server上的多个bean中创建和调用方法的事务。 . 一个在其他的server上调用其他EJB的方法的bean的方法。 对于这些工作厂商必须为EJBObject生成stub和skeleton来隐式地获得当前事务的上下文,同时将其通过方法调用传到远程bean。当将商务方法调用委派给bean时,远程bean的EJBObject的skeleton必须请求这个事务的上下文。 Enterprise JavaBeans导论一 Enterprise JavaBeans导论二 Enterprise JavaBeans导论三 Enterprise JavaBeans导论四 Enterprise JavaBeans导论五 Enterprise JavaBeans导论六 Enterprise JavaBeans导论七 <

小小豆叮