一、内容简介
Steven Gould
在文中介绍了
J2EE
的
13
种核心技术:
JDBC
、
JNDI
、
EJBs
、
RMI
、
JSP
、
Java Servlets
、
XML
、
JMS
、
Java IDL
、
JTS
、
JTA
、
JavaMail
和
JAF
。为了联系实际,
Gould
基于
WebLogic
应用服务器来自
BEA Systems
公司的一种广为应用的产品环境来介绍
J2EE
的这些技术。
Java
最初在浏览器和客户端机器中粉墨登场,当时很多人质疑它是否适合做服务器端的开发。现在随着对
J2EE
第三方支持的增多,
Java
被广泛接纳为开发企业级服务器端解决方案的首选平台之一。
J2EE
平台由一整套服务
(Services)
、应用程序接口
(APIs)
和协议构成,它对开发基于
Web
的多层应用提供了功能支持。在本文中我将解释支撑
J2EE
的
13
种核心技术:
JDBC
、
JNDI
、
EJBs
、
RMI
、
JSP
、
Java Servlets
、
XML
、
JMS
、
Java IDL
、
JTS
、
JTA
、
JavaMail
和
JAF
,同时还将描述在何时、何处需要使用这些技术。当然我还要介绍这些不同技术之间如何交互。
此外,为了让您更好地感受
J2EE
的真实应用,我将在
WebLogic
应用服务器环境下来介绍这些技术。不论对于
WebLogic
应用服务器和
J2EE
的新手,还是那些想了解
J2EE
能带来什么好处的项目管理者和系统分析员,相信本文一定很有参考价值。
二、宏观印象
:
分布式结构和
J2EE
过去二层化应用
--
通常被称为
C/S
应用
--
是大家谈论最多的。在很多情况下,服务器提供的唯一服务就是数据库服务。在这种解决方案中,客户端程序负责数据访问、实现业务逻辑、用合适的样式显示结果、弹出预设的用户界面、接受用户输入等。
C/S
结构通常在第一次部署时较容易,但难于升级或改进,且经常基于某种专有的协议,通常是某种数据库协议。它使得重用业务逻辑和界面逻辑非常困难。更重要的是,在
Web
时代,二层化应用通常不能体现出很好的伸缩性,因而很难适应
Internet
的要求。
Sun
设计
J2EE
的部分起因就是想解决二层结构的缺陷,于是
J2EE
定义了一套标准来简化
N
层企业级应用的开发。它定义了一套标准化组件,并为这些组件提供完整的服务。
J2EE
还自动为应用程序处理了很多实现细节,如安全、多线程等。用
J2EE
开发
N
层应用包括将二层结构中的不同层面切分成许多层。一个
N
层化应用
A
能够为以下的每种服务提供一个分开的层:
显示:在一个典型
Web
应用中,客户端机器上运行的浏览器负责实现用户界面。
动态生成显示:尽管浏览器可以完成某些动态内容显示,但为了兼容不同的浏览器,这些动态生成工作应该放在
Web
服务器端进行,使用
JSP
、
Servlets
或
XML
和
XSLT
。
业务逻辑:业务逻辑适合用
Session EJBs(
后面将介绍
)
来实现。
数据访问:数据访问适合用
Entity EJBs(
后面将介绍
)
和
JDBC
来实现。
后台系统集成:同后台系统的集成可能需要用到许多不同的技术,至于何种最佳,需要根据后台系统的特征而定。
您可能开始诧异:为什么有这么多的层?事实上,多层方式可以使企业级应用具有很强的伸缩性,它允许每层专注于特定的角色。如让
Web
服务器负责提供页面,应用服务器处理应用逻辑,而数据库服务器提供数据库服务。
由于
J2EE
建立在
J2SE
的基础上,所以具备了
J2SE
的所有优点和功能。包括
“
编写一次,到处可用
”
的可移植性、通过
JDBC
访问数据库、同原有企业资源进行交互的
CORBA
技术,及一个经过验证的安全模型。在这些基础上,
J2EE
又增加了对
EJB
、
Java Servlet
、
JSP
和
XML
技术的支持。
三、分布式结构与
WebLogic
应用服务器
J2EE
提供了一个框架
(
一套标准
API)
用于开发分布式结构的应用,这个框架的实际实现留给了第三方厂商。部分厂商只是专注于整个
J2EE
架构中的的特定组件,如
Apache
的
Tomcat
提供了对
JSP
和
Servlet
的支持,
BEA
系统公司则通过其
WebLogic
应用服务器产品为整个
J2EE
规范提供了一个较为完整的实现。
WebLogic
服务器已使建立和部署伸缩性较好的分布式应用的过程大为简化。
WebLogic
和
J2EE
代你处理了大量常规的编程任务,包括提供事务服务、安全领域、可靠的消息、名字和目录服务、数据库访问和连接池、线程池、负载平衡和容错处理等。通过以一种标准、易用的方式提供这些公共服务,象
WebLogic
服务器这样的产品造就了具有更好伸缩性和可维护性的应用系统,使其为大量的用户提供了增长的可用性。
四、
J2EE
技术
在接下来的部分里,我们将描述构成
J2EE
的各种技术,且了解
WebLogic
服务器是如何在一个分布式应用中对它们进行支持的。最常用的
J2EE
技术应该是
JDBC
、
JNDI
、
EJB
、
JSP
和
Servlets
,对这些我们将作更仔细的考察。
1. Java Database Connectivity (JDBC)
JDBC API
以一种统一的方式来对各种数据库进行存取。和
ODBC
一样,
JDBC
为开发人员隐藏了不同数据库的不同特性。另外,由于
JDBC
建立在
Java
的基础上,因此还提供了数据库存取的平台独立性。
JDBC
定义了
4
种不同的驱动程序,现分述如下:
类型
1
:
JDBC-ODBC Bridge
在
JDBC
出现的初期,
JDBC-ODBC
桥显然是非常有实用意义的,通过
JDBC-ODBC
桥,开发人员可用
JDBC
来存取
ODBC
数据源。不足的是需要在客户端安装
ODBC
驱动程序,换句话说,必须安装
Windows
的某个版本。使用这一类型要牺牲
JDBC
的平台独立性。另外
ODBC
驱动程序还需具有客户端控制权限。
类型
2
:
JDBC-native driver bridge
JDBC
本地驱动程序桥提供了一种
JDBC
接口,它建立在本地数据库驱动程序的顶层,而不需要
ODBC
。
JDBC
驱动程序将对数据库的
API
从标准的
JDBC
调用转换为本地调用,使用此类型要牺牲
JDBC
的平台独立性,还要求在客户端安装客户端数据库驱动程序。
类型
3
:
JDBC-network bridge
JDBC
网络桥驱动程序不需要客户端数据库驱动程序。它使用网络上的中间件服务器来存取数据库。这种应用使得负载均衡、连接缓冲池和数据缓存等技术的实现有了可能。由于第
3
种类型往往只需要相对更少的下载时间,具有平台独立性,且不需要在客户端安装数据库驱动程序并取得控制权,所以很适合于
Internet
上的应用。
类型
4
:
Pure Java driver
通过使用一个纯
Java
数据库驱动程序来执行数据库的直接访问。此类型实际上在客户端实现了
2
层结构。要在
N-
层结构中应用,一个更好的做法是编写一个
EJB
,让它包含存取代码并提供一个对客户端具有数据库独立性的服务。
WebLogic
服务器为一些通常的数据库提供了
JDBC
驱动程序,包括
Oracle
、
Sybase
、
Microsoft SQL Server
及
Informix
。它也带有一种
JDBC
驱动程序用于
Cloudscape
,这是一种纯
Java
的
DBMS
,
WebLogic
服务器中带有该数据库的评估版本。让我们看一个实例。
JDBC
实例
在这个例子中假定已在
Cloudscape
中建立了一个
PhoneBook
数据库,且包含一个表名为
CONTACT_TABLE
的表,它带有
2
个字段:
NAME
和
PHONE
。开始时先装载
Cloudscape JDBC driver
,并请求
driver manager
得到一个对
PhoneBook Cloudscape
数据库的连接。通过这一连接,可构造一个
Statement
对象并用它来执行一个简单的
SQL
查询。最后用循环来遍历结果集的所有数据,并用标准输出将
NAME
和
PHONE
字段的内容进行输出。
import java.sql.*;
public class JDBCExample{
public static void main(String args[]){
try{
Class.forName("COM.cloudscape.core.JDBCDriver");
Connection conn = DriverManager.getConnection("jdbc:cloudscape honeBook");
Statement stmt = conn.createStatement();
String sql = "SELECT name, phone FROM CONTACT_TABLE ORDER BY name";
ResultSet resultSet = stmt.executeQuery(sql);
String name, phone;
while (resultSet.next()){
name = resultSet.getString(1).trim();
phone = resultSet.getString(2).trim();
System.out.println( name + ", " + phone );
}
}
catch ( Exception e ){
// Handle exception here
e.printStackTrace();
}
}
}
接着我们来看一看
JDBC
是如何在企业应用中的进行使用。
JDBC
在企业级应用中的应用
以上实例其实是很基本的,可能有些微不足道,它假定了一个
2
层结构。在一个多层的企业级应用中,更大的可能是在客户端和一个
EJB
进行通信,该
EJB
将建立数据库连接。为了实现和改进可伸缩性和系统性能,
WebLogic
服务器提供了对连接缓冲池
Connection pool
的支持。
Connection pool
减少了建立和释放数据库连接的消耗。在系统启动以后即可建立这样的缓冲池,此后如故再有对数据库的请求,
WebLogic
服务器可很简单地从缓冲池中取出数据。数据缓冲池可在
WebLogic
服务器的
weblogic.properties
文件中进行定义
(
可参考
weblogic.properties
文件中的例子,
WebLogic
服务器的文档中还有更详细的参考信息
)
。
在企业级应用的另一个常见的数据库特性是事务处理。事务是一组申明
statement
,它们必须作为同一个
statement
来处理以保证数据完整性,缺省情况下
JDBC
使用
auto-commit
事务模式。这可以通过使用
Connection
类的
setAutoCommit()
方法来实现。
2. Java Naming and Directory Interface (JNDI)
JNDI API
被用于执行名字和目录服务。它提供了一致的模型来存取和操作企业级的资源,如
DNS
和
LDAP
、本地文件系统,后者在应用服务器中的对象。
JNDI
中,在目录结构中的每一结点称为
context
。每一个
JNDI
名字都是相对于
context
的。这里没有绝对名字的概念存在。对一个应用来说,它可通过使用
InitialContext
类来得到其第一个
context
:
Context ctx = new InitialContext();
应用可通过这个初始化的
context
经由这个目录树来定位它所需要的资源或对象。如假设你在
Weblogic
服务器中展开了一个
EJB
并将
home
接口绑定到名字
myApp.myEJB
,那么该
EJB
的某个客户在取得一个初始化
context
后,可通过以下语句定位
home
接口:
MyEJBHome home = ctx.lookup( "myApp.myEJB" );
在这个例子中,一旦你有了对被请求对象的参考,
EJB
的
home
接口就可以在它上面调用方法。我们将在下面的
EJB
章节中做更多的介绍。以上关于
JNDI
的讨论只是冰山之一角。如果要进一步地在
context
中查找对象,
JNDI
也提供了一些方法来进行以下操作:
将一个对象插入或绑定到
context
,这在你展开一个
EJB
时很有效。
从
context
中移去对象。
列出
context
中的所有对象。
创建或删除子一级的
context
。
3. Enterprise Java Beans (EJB)
J2EE
技术之所以赢得广泛重视的原因之一就是
EJB
。它们提供了一个框架来开发和实施分布式商务逻辑,由此很显著地简化了具有可伸缩性和高度复杂的企业级应用的开发。
EJB
规范定义了
EJB
组件在何时如何与它们的容器进行交互作用。容器负责提供公用的服务,如目录服务、事务管理、安全性、资源缓冲池及容错性。
EJB
规范定义了
3
中基本的
bean
类型,这里先不谈
Message-driven Bean
:
Stateless session beans
:提供某种单一服务而不维持任何状态,在服务器故障发生时无法继续存在,生命期相对较短。如它可能被用于执行温度转换计算。
Stateful session bean
:提供了与客户端的会话交互,可存储状态从而代表一个客户。典型例子是购物车。不过在服务器故障时无法继续生存,生命期相对较短。每一个实例只用于一个单个的线程。
Entity beans:
提供了一致性数据的表示,通常存放在数据库中,在服务器故障发生后能继续存在。多用户情况下可使用
EJB
来表示相同的数据,
Entity EJB
的一个典型例子是客户的帐号信息。
尽管有以上的区别,所有的
EJB
还是有许多的共同之处。它们都处理
home interface
。它定义了一个客户端是如何创建与消亡
EJB
的。可在
bean
中对定义了客户端方法的远程接口进行调用;
bean
类则执行了主要的商务逻辑。
描述
EJB
的开发已经超出了本文的范围。但如果一个
EJB
已被开发或从第三方购买,它就须在应用服务器中进行发布。
WebLogic Server 5.1
带有一个
EJB Deployer Tool
来协助处理
EJB
的发布。当你使用
EJB Deployer Tool
的时候,你要定义客户端所用的
JNDI
名字来定位
EJB
。
Deployer Tool
将生成
wrapper
类来处理和容器的通信及在一个
jar
文件中把被请求的
Java
类绑定在一起。
一旦
EJB
被发布,客户端就可以使用它的
JNDI
名字来定位
EJB
。首先它必须得到一个到
home
接口的
reference
。然后客户端可使用该接口,调用一个
create()
方法来得到服务器上运行的某个
bean
实例的句柄;最后客户端可以使用该句柄在
bean
中调用方法。
4. JavaServer Pages (JSPs)
我们中可能已有许多人熟悉
Microsoft
的
ASP
技术。
JSP
和
ASP
相对应,但更具平台独立性。他们被设计用以帮助
Web
内容开发人员创建动态网页,且只需要相对较少的代码。
即使
Web
设计师不懂得如何编程也可使用
JSP
,因为
JSP
应用是很方便的。
JSP
页面由
HTML
代码和嵌入其中的
Java
代码所组成。服务器在页面被客户端所请求后对这些
Java
代码进行处理,然后将生成的
HTML
页面返回给客户端的浏览器。
您可能听说过
JHTML
,这是
JSP
前一种较老标准。
WebLogic
服务器可支持两者。请注意在缺省状况下,
JSP
在
WebLogic
服务器中并没有处于有效状态。要使之有效,你可以编辑
weblogic.properties
文件。如果
Web
服务器还没有处于有效状态,则要先使之有效。
Servlet
的情况和
JSP
一样。
5. Java servlets
servlet
提供的功能大多与
JSP
类似,不过实现方式不同。
JSP
通常是大多数
HTML
代码中嵌入少量的
Java
代码,而
servlets
全部由
Java
写成并且生成
HTML
。
servlet
是一种小型的
Java
程序,它扩展了
Web
服务器的功能。作为一种服务器端应用,当被请求时开始执行,这和
CGI Perl
脚本很相似。
Servlets
和
CGI
脚本的一个很大的区别是:每一个
CGI
在开始时都要求开始一个新进程,而
servlets
在
servlet
引擎中以分离的线程来运行。因此其在可伸缩性上提供了很好的改进。
在开发
servlets
时,常需扩展
javax.servlet.http.HttpServlet
类,且
override
一些它的方法,其中包括:
service()
:作为
dispatcher
来实现命令
-
定义方法
doGet():
处理客户端的
HTTP GET
请求。
doPost():
进行
HTTP POST
操作
其它的方法还包括处理不同类型的
HTTP
请求,可参考
HttpServlet API
文档。
以上描述是标准
J2EE Servlet API
的各种方法。
WebLogic
服务器提供了一个该
API
完整的实现途径。一旦你开发了一个
servlet
,就可以在
weblogic.properties
中加以注册并由此可以在
WebLogic
服务器中对它进行配置。
6. Remote Method Invocation(RMI)
在远程对象上调用一些方法,使用连续序列方式在客户端和服务器端传递数据。
RMI
是一种被
EJB
使用的更下层的协议。
【
远程方法调用(RMI,Remote Method Invocation)是jdk1.1中引入的分布式对象软件包,它的出现大大简化了分布异构环境中Java应用之间的通信。
要使用RMI,必须构建四个主要的类:远程对象的本地接口、远程对象实现、RMI客户机和RMI服务器。RMI服务器生成远程对象实现的一个实例,并用一个专有的URL注册。RMI客户机在远程RMI服务器上查找服务对象,并将它转换成本地接口类型,然后像对待一个本地对象一样使用它。
下面是一个简单的RMI实例,RMI客户机通过RMI服务器提供的方法输出一个语句。例子虽然很简单,但掌握了Java RMI调用的基本原理和方法,在实现复杂应用时,我们需要做的也只是完善远程对象的实现类而已。
1.远程对象的本地接口声明(RMIOperate.java)
· 该类仅仅是一个接口声明,RMI客户机可以直接使用它,RMI服务器必须通过一个远程对象来实现它,并用某个专有的URL注册它的一个实例。
java.rmi.Remote
接口。
java.rmi.RemoteException
(或
RemoteException
的父类)。
Hello.java
|
/*
* @author javamxj (CSDN Blog) 创建日期 2004-12-27
*/
import
java
.
rmi
.
*
;
// RMI本地接口必须从Remote接口派生
public
interface
Hello
extends
Remote {
// 接口中的具体方法声明,注意必须声明抛出RemoteException
String
sayHello(
String
name)
throws
RemoteException
; }
|
这个类应实现RMI客户机调用的远程服务对象的本地接口,它必须从UnicastRemoteObject继承,构造函数应抛出RemoteException异常。
HelloImpl.java |
/*
* @author javamxj (CSDN Blog) 创建日期 2004-12-27
*/
import
java
.
rmi
.
*
;
import
javax
.
rmi
.
PortableRemoteObject
;
public
class
HelloImpl
extends
PortableRemoteObject
implements
Hello {
/* 构造函数 */
public
HelloImpl()
throws
RemoteException
{
super
(); }
/* 实现本地接口中声明的'sayHello()'方法 */
public
String
sayHello(
String
message)
throws
RemoteException
{
System
.out.println(
"我在RMI的服务器端,客户端正在调用'sayHello'方法。 "
);
System
.out.println(
"Hello "
+ message);
return
message; }}
|
该类创建远程对象实现类HelloImpl的一个实例,然后通过一个专有的URL来注册它。所谓注册就是通过Java.rmi.Naming.bind()方法或Java.rmi.Naming.rebind()方法,将HelloImpl实例绑定到指定的URL上。
HelloServer.java |
/* * @author javamxj (CSDN Blog) 创建日期 2004-12-27 */ import java . rmi . * ; public class HelloServer { public static void main( String [] args) { // 在服务器端设置安全机制 /* if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } */ try { System .out.println( "开始 RMI Server ..." ); /* 创建远程对象的实现实例 */ HelloImpl hImpl = new HelloImpl(); System .out.println( "将实例注册到专有的URL " ); Naming .rebind( "HelloService" , hImpl); System .out.println( "等待RMI客户端调用..." ); System .out.println( "" ); } catch ( Exception e) { System .out.println( "错误: " + e); } } } |
请注意有关
rebind
方法调用的下列参数:
-
第一个参数是 URL 格式的
java.lang.String
,表示远程对象的位置和名字。-
需要将
myhost
的值更改为服务器名或 IP 地址。否则,如果在 URL 中省略,则主机缺省值为当前主机,而且在 URL 中无需指定协议(例如“HelloServer
”)。 -
在 URL 中,可以选择提供端口号:例如“/
/myhost:1234/HelloServer”。
端口缺省值为 1099。除非服务器在缺省 1099 端口上创建注册服务程序,否则需要指定端口号。
-
-
第二个参数为从中调用远程方法的对象实现引用。
-
RMI 运行时将用对远程对象 stub 程序的引用代替由
hImpl
参数指定的实际远程对象引用。远程实现对象(如HelloImpl
实例)将始终不离开创建它们的虚拟机。因此,当客户机在服务器的远程对象注册服务程序中执行查找时,将返回包含该实现的 stub 程序的对象。
· RMI客户使用java.rmi.Naming.lookup()方法,在指定的远程主机上查找RMI服务对象,若找到就把它转换成本地接口RMIOperate类型。它与CORBA不同之处在于RMI客户机必须知道提供RMI服务主机的URL,这个URL可以通过rmi://host/path或rmi://host:port/path来指定,如果省略端口号,就默认使用1099。
HelloClient.java |
/* * @author javamxj (CSDN Blog) 创建日期 2004-12-27 */ import java . rmi . * ; public class HelloClient { public static void main( String [] args) { // 在服务器端设置安全机制 /* if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } */ /* 默认为本地主机和默认端口 */ String host = "localhost:1099" ; /* 带输入参数时,将host设置为指定主机 */ if (args.length > 0) host = args[0]; try { /* 根据指定的URL定位远程实现对象 */ /* “h”是一个标识符,我们将用它指向实现“Hello”接口的远程对象 */ Hello h = (Hello) Naming .lookup( "rmi://" + host + "/HelloService" ); System .out.println( "实现“Hello”接口的远程对象: " + h); System .out.println( "我在客户端,开始调用RMI服务器端的'sayHello'方法" ); System .out.println( "欢迎, " + h.sayHello( "javamxj blog" )); } catch ( Exception ex) { System .out.println( "错误 " + ex); } } } |
(2).生成客户端存根和服务器框架
D:\RMISample\server>rmiregistry
● 在服务器上执行HelloServer
D:\RMISample\server>java HelloServer
D:\RMISample\client>java HelloClient
java HelloClient 222.222.34.34
permission java.security.AllPermission "", "";
};
】
7. Java IDL/CORBA
在
Java IDL
的支持下,开发人员可以将
Java
和
CORBA
集成在一起。
他们可创建
Java
对象并使之可在
CORBA ORB
中展开,或可创建
Java
类并作为和其它
ORB
一起展开的
CORBA
对象的客户。后一种方法提供了另外一种途径,通过它
Java
可以被用于将你的新的应用和
legacy
系统相集成。
8. Java Transaction Architecture (JTA)/Java Transaction Service (JTS)
JTA
定义了一种标准的
API
,应用系统由此可存取各种事务监控。
JTS
是
CORBA OTS
事务监控的基本的实现,
JTS
规定了事务管理器的实现方式。该事务管理器是在高层支持
Java Transaction API (JTA)
规范,且在较底层实现
OMG OTS specification
的
Java
映像。
JTS
事务管理器为应用服务器、资源管理器、独立的应用及通信资源管理器提供了事务服务。
9. JavaMail and JavaBeans Activation Framework
JavaMail
是用于存取邮件服务器的
API
,它提供了一套邮件服务器的抽象类。不仅支持
SMTP
服务器,也支持
IMAP
服务器。
JavaMail
利用
JavaBeans Activation Framework (JAF)
来处理
MIME-
编码的邮件附件。
MIME
的字节流可被转换成
Java
对象或转换自
Java
对象。由此大多数应用都可不需要直接使用
JAF
。
10. Java Messaging Service (JMS)
JMS
是用于和面向消息的中间件相互通信的应用程序接口
(API)
。它既支持点对点的域,有支持发布
/
订阅
(publish/subscribe)
类型的域,且提供对下列类型的支持:经认可的消息传递、事务型消息的传递、一致性消息和具有持久性的订阅者支持。
JMS
还提供另种方式来对您的应用与
legacy backend
系统相集成。
11. Extensible Markup Language (XML)
XML
是一种可用来定义其它标记语言的语言,它被用来在不同的商务过程中共享数据。
XML
的发展和
Java
是相互独立的,但它和
Java
具有的相同目标,即平台独立性。通过将
Java
和
XML
的组合,可得到一个完美的具有平台独立性的解决方案。目前正有许多不同的公司在为
Java
和
XML
的组合而努力。如果要了解更多的这方面的信息,可访问
Sun
的
Java-XML
页面或
IBM developerWorks
的
XML Zone
。
五
总结
本文介绍了建立在
J2EE
上的分布式应用结构,且描述了
WebLogic
服务器对
J2EE
的各种支持。
然而,我们所揭示的仅是冰山之一角而已,要以一篇数千字的文章来展示
J2EE
潜在的对您的企业级应用的影响可是很不公平的。
我们已经关注了在您开始
J2EE
进行工作时最有可能遇到的各类技术:
JDBC
、
JNDI
、
EJB
、
JSP
和
servlet
。我们也为您提供了一些尚未常见的
J2EE
技术的背景知识。不管您是一名开发人员、商务应用分析师或项目经理,都应对
J2EE
和
WebLogic
服务器所能提供给我们的企业级应用所带来的意义有一个更好的认识。