您的当前位置:首页正文

分布式应用程序开发

2020-05-04 来源:步旅网
大型Java分布式应用纵横谈

在当今应用架构里,分布式应用与服务之间的通信都是核心思想。想要从分布式应用与服务中获益,你必须牢牢记住几条基本的原则,否则你可能很容易遇到性能和扩展性问题。在开发阶段这些问题不会经常出现,但当你进行负载测试或产品化的时候,你会意识到你选择的软件架构不能满足性能和扩展性需求。在这篇文章中,我们重点关注构建分布式应用需要记住的一些关键点。

分布式需要应用之间进行交互。范围包括从大规模集群架构上简单的点到点的交互,到动态的面向服务或基于服务的架构。跨系统边界的通信也是提高软件系统扩展性和可用性的关键。如今软件架构已把分布式作为一个核心的必要的概念。Java平台成为了核心角色,因为它的分布式、有很好的API和产品支持这些特点。应用场景从像SAP这样在标准软件上的系统集成,到内部或外部的服务集成。SOA提供这样的方法,使服务和应用变的灵活和可重用,可以对新的市场需求很快的做响应。另外,像使用网格计算,虚拟机和多核刀片机的趋势,导致越来越多的集群应用的出现。这主要是由于追求高可扩展性和高可用性驱动的。而且云计算的发展趋势表明,分布式平台将来会更加流行。另外,系统正变得希望能更动态的增加其灵活性。例如,在运行时添加应用节点。这些趋势也导致了系统结构变得越来越复杂。对于开发人员,则更难理解产品中服务调用是如何实现的。这种复杂性和缺乏对相应知识的了解,很容易导致资源消耗的增加(CPU,内存,网络)和性能的降低。

如今,远程技术使分布式应用的实现更加简单。底层通信的细节和服务端和客户端的基础结构对开发人员是透明的。现在,如果要把一个Java类暴露为一个服务,有时只需要简单的加一个注解到这个类上。服务也可以被工具生成的代理很容易的访问。如下图所示,但是,这仅仅是冰山的一角。

图1.远程协议的上层架构

远程堆栈的核心块是对象的序列化和传输的格式化。通常,应用的开发者不需要知道这些。但是,这也是很多性能问题产生的原因。效率不高的序列化意味着,通过网络传输了很多不需要的数据。复杂对象的显示和大量的数据,在序列化和反序列化期间,导致CPU和内存的使用会很高。底层的基础架构和它的配置对应用的性能有很大的影响。在客户端,主要是连接的管理和底层线程模型。在分布式应用中使用连接的指导方针和数据库的连接很像。建立一个连接需要一定的时间。但这同样要看是什么协议。例如,建立一个HTTPS的连接的开销要大于一个简单的TCP/IP连接。同时连接又是系统很重要的资源。所以使用连接池很重要。正确的配置在这里也很关键,因为错误的配置文件给我们带来的坏处要多于好处。线程的模型涉及到请求如何被处理。重要的是请求是被同步还是异步处理。同步通信阻塞一个进程直到收到相应。在异步通信中,当收到响应时会调用一个回调。这就允许这个线程被

其他事务使用。在服务端,可用的工作线程数量就是定义的并行处理的最大服务请求数。网络本身也是分布式应用的一个重要组件。网络是比影响性能更加限制其可扩展性的重要的瓶颈资源。这块通常在开发时会被忽视,因为没有调用实际的网络。 远程调用之美在于...

这有很多可以选择,Java提供了非常多的可能性和技术来实现分布式应用。远程技术的选择对应用的架构、性能和扩展性有十分重要的影响。最“老的”的但是几乎是用的最广的远程协议是RMI(如下图)。

图2.RMI架构

RMI是J2EE应用的一个标准协议,设计时就是为了调用远程Java虚拟主机上的对象提供的方法。对象在服务端被暴露出来,这时客户端就可以通过代理调用这个对象。同样的服务端对象被多个线程使用。线程池被RMI基础设施管理。通信通过TCP/IP被处理,并且使用JRMP或针对RMI的基于IIOP GIOP(CORBA协议)的协议。应用服务端也提供自己的属性协议来优化其性能。如服务端的引用需要管理一样,RMI基础设施也提供了垃圾回收器来管理引用。这个分布式垃圾回收器(DGC)本身也使用RMI协议来管理服务器端的对象生命周期。除了客户端和服务端很强大,RMI还有一些其他的实现。关于RMI的详细介绍及应用请参考51CTO之前的文章《用RMI实现基于Java的分布式计算》。

RMI只支持同步通信,缺点上面已经讨论过了。另外,不能为数据驱动的服务提供低级缓存,因为它是基于2进制协议的。开发人员和系统架构能够改变基础设施的配置参数来优化性能。JMS是J2EE平台上使用的第二多的协议。如下图:

图3.JMS架构图

有别于RMI, JMS是一个异步协议。通信是基于队列的,以便监听器可以对消息作出反应。JMS不是一种标准的远程调用协议,但是它仍然能够满足服务与服务之间的交互。在SOA中非常重要的很多ESB的实现,就采用基于JMS的中间件来进行服务之间的信息传递。由于JMS是异步的,一些典型的同步问题就可以避免。在很多系统中,高可扩展性的关键在于能够很快的释放资源(像线程)。在很多情况下,异步处理是唯一合适的方法。JMS提供很多不同的传输格式。XML是最通用的消息格式,但二进制格式也是可能的。消息结构的设计是应用架构的一个重要部分,因为它可以直接影响到应用的性能和可扩展性。

基于SOAP的WEB Service(如下图)和其他相关的WS-*也在Java 企业应用领域中变得越来越重要。

图4.同步和异步SOAP架构

设计SOAP是为了替换CORBA,而且一开始就得到了业界的强烈支持。因为WS-I之间的共同努力,不同平台差不多能够很容易的连接起来。SOAP是一种基于XML的RPC协议,所以很容易和浪费带宽联系到一起。 越来越多的基于REST的服务开始取代SOAP。Java中的REST服务在JSR 311中有说明,是基于HTTP所支持的基本操作而设计的。但是,REST不是作为RCP协议,而是面向资源的,为了访问和操作(web)资源而设计的。这两个协议都支持同步通信。这也是底层HTTP协议所要求的。WS-地址对SOAP协议进行扩展,所以它也允许异步服务的实现。REST最大的优点是,能够很容易的通过HTTP代理实现缓存。REST依靠使用HTTP底层协议,无论如何都和用的机制。 可能犯的错

分布式应用的很多地方都可能出现潜在的问题,如图所示:

图5 分布式应用的问题起因

在客户端,主要的问题在于糟糕的交互设计-太多的服务调用,或者选择了错误的通信模式。同步事务运行时间过长很容易导致性能问题。在通信层,大量的数据和过多的服务调用所产生的高的网络负载是主要问题。在服务端,不适当的服务接口设计和不合适的序列化策略的使用导致性能和扩展性问题。我们下面仔细看下这些问题。 分布式应用的问题起因

通信协议的正确选择主要取决于系统的整体架构和底层的需求。如果你工作在有mainframe、Java和.NET组件相互交互的特异环境中,用SOAP是行不通的。在纯Java环境中,在JRMP上使用RMI仍是性能最优,可扩展性最好的解决方案,你能够获得开箱即用的编程支持。在很多SOA实现中,SOA和基于Web Service的实现同义而语。所以有越来越多的使用SOAP作为RPC协议的纯Java应用案例出现,尽管采用这样的方法一点有点都没有。调查显示,和RMI-JRMP相比,经常使用SOAP还是有意义的。除了描述过的标准协议,一些其他的基于XML的和二进制协议也在一些应用中使用。Hessian的性能就不错。另外,还有一些其他编程语言的实现。例如使用Spring把POJOs暴露给远程调用使不改变实现就在不同的协议间切换变得相对容易。Spring 支持RMI, HTTP, Hessian, Burlap, JAX-RPC, JAX-WS 和 JMS。 反模式:饶舌的应用

在搭建分布式应用时,一个核心的原则就是尽量减少远程调用。这些意味着数据序列化的开销,建立连接的开销和附件的网络负载。另外,CPU,内存和网络资源的消耗限制了可扩展性。所以,为远程应用的接口设计一种方法,来确保必要的服务交互数最小是十分重要的。尤其是那些起初是在本地搭建的,然后为了可扩展性原因遭遇了大量服务交互的应用。这些问题大多会在负载测试或产品化时出现,但当本地开发测试时一点问题都没有。可以采用适当的性能管理方法,在开发过程中分析远程行为就可以避免这些问题。下图显示的是一个通过dynaTrace分析一个应用的远程行为的例子 。

基于这个分析,接口能够重新创建,应用逻辑能够重新设计来减少远程调用的次数。可能的方法是,合并几个方法的逻辑为一个,或在几个调用请求周边的对象处,使用数据容器。特定数据的位置也可以帮助减少远程调用,因为在需要的地方数据是可用的。尤其当读数据时,使用cache可以很大程度上提高性能和可扩展性。在软件设计的早期,服务的分发和可能的通信在成为需求或将成为需求时已经考虑到是很重要的。 反模式:大格式消息

当调用远程的服务时,这通常意味着数据会在不同的协议上传输。像XML在SOAP协议上传输或二进制数据在RMI协议上传输。大多数技术传输对象的数据或对象本身。大多数情况下,序列化的发生是在远程实现的底层。序列化的开销和所传输对象的大小相对应。在实际情况下,我们进行序列化的开销要占到98%。怎么会这样?一个鉴权服务接口需要一个用户对象来授权。这个用户对象不仅有用户名和密码,还有很多属性,关联到其他用例的数据引用。标准的SOAP序列化要创建几千字节的数据消息。这些数据要被服务解析并映射到用户对象结构上,导致大量CPU和内存的消耗。解决方案再明显不过了。接口要重构,只需要用户ID和密码。所以,除了选择正确的远程技术,消息内容的设计对构建好的性能和可扩展性的应用很重要。通常正好符合设计的很好一般对象会带来高性能的回报。

反模式:分布部署

分布式的Java企业级应用会导致一个应用分割成多个服务和一些部署单元部署到一些应用服务上。分布式的有一个组件新的部署包不需要重新部署到其他组件上。另一个可能性是,大量使用的服务能够部署到独立的硬件或被部署多次。有大量部署单元的复杂应用,服务的交互变得越来越难理解。这会导致2个交互频繁的服务被部署到不同的硬件上从而产生很多的远程调用情况出现。在大规模应用中,分析交互的频率和数据大小与部署结构一致是很重要的。很多时候,从分布式部署到本地可以使性能得到很大的提升而不需要损失灵活性和可扩展性。尤其对那些无状态的服务,把它们部署到不同的节点来提升其本地性。 结论

从这些反模式中可以看出,在应用的设计初期阶段就考虑可扩展性是很重要的。它是应用架构的一个关键驱动。在后期提高性能和可扩张性在多数或大多数情况下工作会越困难。对应用产品的详细分析来识别远程调用的频率或大体积数据,优化系统的一致性是不可或缺的。如果你遇到了相似的或不同的问题,请让我知道,我好扩充我的反模式记录。 \\

分布式系统的数据复制技术

一个中型或大型公司往往由地理上分散的部门所组成,这些部门通常需要进行数据共享。针对这些共享数据,可以将其存储在某个站点上,需要的用户都从这个站点上存取。这种方案的优点是数据的一致性容易保证,但其缺点也是很突出的,那就是该站点的负载大、网络负载大,远程用户的数据响应迟缓。数据复制技术可以有效地解决这个问题,它通过将这些共享数据复制到位于不同地点的多个数据库中,从而实现数据的本地访问,减少了网络负荷,并提高了数据访问的性能,而且通过对数据库中的数据定期同步(通常是每天晚上),从而确保了所有的用户使用同样的、最新的数据。该技术适用于用户数量较大、地理分布较广、而且需要实时地访问相同数据的应用模式。 数据复制的概念及特点 1、数据复制的概念及分类

数据复制,就是将数据库中的数据拷贝到另外一个或多个不同的物理站点上,从而保持源数据库与目标数据库中指定数据的一致性。

按照数据复制的实时性,数据复制可分为同步数据复制和异步数据复制。同步数据复制是指将本地生产数据以完全同步的方式复制到异地,每一本地IO交易均需等待远程复制的完成方予以释放。异步数据复制则是指将本地的所生产的数据以后台同步的方式复制到异地,每一本地IO交易均正常释放,无需等待远程复制的完成。同步复制实时性强,远端数据与本地数据完全同步。但这种方式受带宽影响较大,数据传输距离较短。异步复制不影响本地交易,传输距离长,但其数据比本地数据略有延迟。异步复制环境中,对于所有应用最关键的就是要确保数据的一致性。

按照复制站点的类型,数据复制可分为多主控站点复制、物化视图复制及混合复制。多主控站点复制也称为对等站点复制,其中每个站点都是主控站点,都需要与其他站点进行信息交流,各站点之间是平等的。物化视图复制包含一个主控站点、一个或多个物化视图站点,

物化视图中的内容可以为目标主对象在某个时间点的全部拷贝或部分拷贝,其中目标主对象既可以是主控站点上的表也可以是物化视图站点上的主物化视图。混合复制包含多个主控站点和多个物化视图站点,是主控站点复制和物化视图复制的结合体,适合于复杂的业务情况。 2、数据复制的特点

数据复制通过在多个站点上建立备份,能够提高数据的安全性,同时也提高了数据的可用性,这是因为如果一个站点出现了问题,用户可以选择其他站点继续进行操作,应用系统还可继续运行,因此数据复制提供了容错保护机制。 数据复制最基本的功能是提高数据库的性能。它通过将远程数据库中的数据复制到本地,使得应用能够就近访问数据,从而降低网络传输负载,提高效率。而且在数据复制系统中,可以提供多个站点之间的负载平衡,让这几个用户使用这个服务器,另外几个用户可以使用其他的服务器,以避免某些站点负载过重。

物化视图还提供了按子集进行复制,这样各站点就可只复制自己需要的数据,也能减轻网络的传输量。

数据复制的实现方法

在具体的实现之前,首先要做好设计与规划。这就需要细致分析具体的业务情况,设计出一套能够满足业务需要的方案。通常在设计过程中,需要确定出要建立的数据库站点,各站点的类型,需要复制的数据对象,以及同步方式、冲突解决方案等内容。在设计完成之后,就可具体来实现数据复制,实现主要包括以下几步: (1)创建复制站点 (2)创建组对象 (3)配置冲突解决方案

下面我们举一个例子来说明各步具体需要完成的工作。在这个例子中我们采用多主控站点复制方式,设有两个主控站点和两个共享数据表。两个主控站点分别为:处理站点(cl.world)和解释站点(js.wo rld);两个数据表为测区( survey)和测线( line)。 STEP1 创建复制站点

(1)首先以SYSTEM身份登陆主站点数据库cl.worldCONNECT system/manager@cl.world

(2)创建用户―复制管理员,并为该用户授权复制管理员负责复制站点的创建和管理,每个复制站点都必须创建复制管理员:

CREATE USER repadmin IDENTIFIED BY repadmin; BEGIN

DBMS_REPCAT_ADMIN.GRANT_ADMIN_ANY_SCHEMA (username => ‟repadmin‟); END;

(3)为本站点指定传播者

传播者负责将本地最新更新的数据传播到其他站点上: BEGIN

DBMS_DEFER_SYS.REGISTER_PROPAGATOR (username => ‟repadmin‟); END;

(4)为本站点指定接收者

接收者负责接收其他站点上的传播者传送过来的数据: BEGIN

DBMS_REPCAT_ADMIN.REGISTER_USER_REPGROUP ( username => ‟repadmin‟,

privilege_type => ‟receiver‟, list_of_gnames => NULL); END;

(5)确定清除时间

为了使传送过来事务队列不致过大,需要将成功加载的事务从事物队列里清除掉,这里设定每小时清除一次。 CONNECT repadmin/repadmin@cl.world BEGIN

DBMS_DEFER_SYS.SCHEDULE_PURGE ( next_date => SYSDATE, interval => ‟SYSDATE + 1/24‟, delay_seconds => 0); END;

在建立好站点cl.world后,以同样的方法创建站点js. world。 (6)创建各主控站点之间的调度链接

创建各主控站点之间的调度链接需要先在各主控站点间建立数据库链接,之后为每个数据库链接定义调度时间。 首先,在处理站点上建立与解释站点的数据库链接,这里需要先建立一个公用数据库链接,供其他私有数据库链接来使用。

CONNECT SYSTEM/MANAGER@cl.world

CREATE PUBLIC DATABASE LINK js.world USING ‟js.world‟; CONNECT repadmin/repadmin@cl.world

CREATE DATABASE LINK js.world CONNECT TO repadmin IDENTIFIED BY repadmin;

同样,在解释站点上建立与处理站点的数据库链接 CONNECT SYSTEM/MANAGER@js.world

CREATE PUBLIC DATABASE LINK cl.world USING ‟cl.world‟; CONNECT repadmin/repadmin@js.world

CREATE DATABASE LINK cl.world CONNECT TO repadmin IDENTIFIED BY repadmin;

调度链接确定本站点上的事务向其他站点发送的频度,下面的代码为10分钟一次: CONNECT repadmin/repadmin@cl.world BEGIN

DBMS_DEFER_SYS.SCHEDULE_PUSH ( destination => ‟js.world‟,

interval => ‟SYSDATE + (1/144)‟, next_date => SYSDATE, parallelism => 1,

execution_seconds => 1500, delay_seconds => 1200); END;

在解释站点上做相同的工作STEP2 创建主控组在复制环境中,Oracle用组来管理复制对象。通过将相关的复制对象放在一个组里,从而方便对大量数据对象的管理。

这里我们假设用户模式integr ation 在处理站点和解释站点都已存在,而且表测区(survey )和测线(line)也已经创建。

(1)创建主控组对象

CONNECT repadmin/repadmin@cl.world BEGIN

DBMS_REPCAT.CREATE_MASTER_REPGROUP ( gname => ‟inte_repg‟); END;

(2)向主控组中添加数据对象,将测区表survey加入到组inte_repg中 BEGIN

DBMS_REPCAT.CREATE_MASTER_REPOBJECT (

gname => ‟inte_repg‟, type => ‟TABLE‟, oname => ‟survey‟, sname => ‟integration‟, use_existing_object => TRUE, copy_rows => FALSE); END;

以同样的方法将测线表line 加入到组inte_repg中

(3)在主控组中添加其他参与复制的站点,数据库之间的同步方式在此指定 BEGIN

DBMS_REPCAT.ADD_MASTER_DATABASE ( gname => ‟inte_repg‟, master => ‟js.world‟,

use_existing_objects => TRUE, copy_rows => FALSE,

propagation_mode => ‟ASYNCHRONOUS‟); END;

(4)如果可能出现冲突,则需要配置冲突解决方案。冲突解决方案将在后面介绍。 (5)为每个对象生成复制支持 BEGIN

DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT ( sname => ‟integration‟, oname => ‟survey‟, type => ‟TABLE‟,

min_communication => TRUE);

END;

测线表line也一样 (6)重新开始复制 BEGIN

DBMS_REPCAT.RESUME_MASTER_ACTIVITY ( gname => ‟inte_repg‟); END;

以同样的方式设置解释站点。设置成功后,数据复制过程就宣告完毕,库中的数据就可进行复制。 数据复制中冲突的解决方案

在复制环境中,尽管在数据库和应用程序设计过程中,会尽量避免各站点间冲突的发生,但完全避免冲突的可能性还是比较小的,那么一旦冲突发生,就需要一个按照具体业务规则的冲突解决机制,来使得各站点的数据保持一致。 首先需要分析哪些对象容易出现冲突。通常来说,静态的数据变化少,冲突出现的可能性也小;而有些数据变化非常大,冲突出现的可能性也大。确定了冲突易发的对象后,需要确定怎样解决冲突,比如在各站点之间建立优先次序,在数据不一致时,以某个站点上的为准;或以某个站点上最新的修改为准。

Oracle提供了多中冲突解决方案,具体包括:针对更新冲突的方案、针对唯一性冲突的方案、针对删除冲突的方案。除了这些方案以外,用户还可以自定义冲突解决方法。每种方案都有自己的适用情况,那么我们需要根据具体的业务来选择合适的冲突解决方案。 结束语

本文详细介绍了分布式系统Oracle中的数据复制技术,在具体应用中,还有许多比较复杂的问题需要解决,比如主控组中如果包含循环依赖的表或自相关的表时如何处理;如何利用模版机制来创建物化视图站点;如何对数据复制环境进行管理与维护。这些问题需要在实际应用中逐步探索,深入研究。

基于J2EE的分布式数据库

拥有地理分散的子公司的企业,地理位置的分散造成了业务数据的分散,总公司与各分公司处于不同的城市或城市中的不同地区,在业务上它们除了处理各自的数据,也需要彼此之间进行数据的交换和处理。笔者论述了使用J2EE技术构建分布式数据库系统的框架模型。 分布式多层体系结构

J2EE(Java2 platform Enterprise Edition)是Sun提出的用于开发和部署三层结构企业级应用的平台,是一整套技术、规范的总称,包括建立企业应用系统的各个方面。使用j2EE技术能够快速建立可伸缩性企业应用系统,其目标是提供一个基于Java语言的服务器应用结构,支持平台独立、可移植、多用户、安全和标准的企业级应用。

J2EE技术的基础就是核心Java或Java 2平台的标准版,J2EE不仅巩固了标准版中的许多优点,如“编写一次到处运行”的特性,方便存取数据库的JDBC API、CORBA技术,以及能够在Internet应用中保护数据的安全模式等;同时还提供了对EJB(Enterprise JavaBeans)、Java ServletsAPI、SP(Java ServerPages)以及XML技术的全面支持。J2EE体系结构如图1所示。

图1:J2EE的体系结构 这种体系结构大致可以定义为客户机上的表示层、中间的业务逻辑层和后台的数据逻辑层。客户端可以先向运行在Web Server上的JavaServlet或者JSP发出请求,在JSP中嵌入Java的代码调用运行在EJB Server中的EJB,以实现商业逻辑。

EJB组件是J2EE的核心,它是基于Java RMI、HOP和JNDI技术,可以分为会话Bean、实体Bean和消息驱动Bean。

会话Bean代理客户端对服务器的请求,模拟商务过程,通过调用实体Bean获得数据,实现业务逻辑的处理流程。实体Bean用来模拟商务数据,是一种在数据存储层中的面向对象的一种内存中的视图和一种将数据持久化的功能和对象的封装性结合的机制,它对应多层应用体系结构中的数据存储层l2 J。

已存在的数据库系统映射到EJB结构可以通过BMP(Bean Managed Persistence)或CMP(ContainerManaged Persistent)完成。消息驱动Bean包含面向消息的逻辑,以及调用会话Bean的逻辑。使用EJB可以获得分布式事务管理、安全检查、资源管理和生命周期、持久性、远程访问能力和位置的透明性 。EJB与客户端及相互之间的交互如图2所示。

图2:EJB与客户及相互之间的交互 分布式数据库系统,是在逻辑上属于同一系统,但在物理上分散在计算机网络连接的多个场地(节点)的一组数据集。系统强调结点的自治性而不强调系统的集中控制,且系统应保持数据的分布透明性,使应用程序编写时可完全不考虑数据的分布情况。

EJB基于RMI/IIOP,具有天生的分布性,EJB容器可以为数据操作提供事务支持,所以可以利用EJB实现分布式数据库系统。

下面分析2种常用设计架构存在的缺陷,提出了使用J2EE实现的分布式数据库系统的架构设计,最后给出了一个设计模型。

两种架构设计方式及其缺点 架构设计方案1

图3:架构1 如图3所示,每个Web服务器除了调用本地数据库外,还调用远程的数据库,将返回来的数据汇总后返回给客户端。此时逻辑代码分散在多个站点的多个Web服务器中,每个Web服务器的调用关系均不同,且当每增加一个数据库时,所有站点的Web服务器上的代码均要改变,加入对新的数据库的调用支持,造成了代码维护困难、可扩充性差、数据库调用逻辑不清晰,实际上形成了一种网状的调用关系。

例如如果新增一个DB4,DB1到DB3上的代码都要改变,增加访问DB4的代码,以提供对DB4的访问支持。 架构设计方案2

在架构1的基础上取消本地的Web服务器,将所有业务逻辑集中到一个Web服务器上,将会消除的网状调用关系,当增加一个新数据库时只需要更改中间的逻辑,从而提高了系统的可扩充性。架构2如图4所示。

图4:架构2 不同的客户端发出访问请求到同一个Web服务器,Web服务器自动区分客户端的来源,按其要求对分布于不同位置的数据源进行访问,汇总结果后返回给用户。

新增一个数据源只需要修改Web服务器上的业务逻辑,但是此时Web将各个分公司的本地数据库与远程数据库同样对待,因为客户端和存放业务逻辑的Web服务器不一定在本地。

当客户仅需要凋用本地数据时,仍然需要访问远程的Web服务器,由Web服务器访问客户的本地数据,再将其返回给本地客户。 链接

数据库技术对数据的收集、存储、处理和传播由集中式走向分布式、从封闭走向开放已在所难免。分布式数据库系统通过复制使系统具有适当的数据冗余,从而增加了系统的可靠性和可用性;提供局部自治的数据共享和场地之问的协调,从而使系统具有快速的数据处理能力。

图5 图6 链接 调用关系: ◆客户发出请求;

◆Web服务器查询本地数据库;

◆本地数据库返回结果;

◆Web服务器将结果格式化后返回给客户端。

Java入门--系统Java基础知识部分总结

1、虽然有很多朋友可能进行了多年的java开发老手,但可能仍旧对某些点缺乏仔细探究。 2、去一些公司求职面试或笔试时的技术题目中,也往往会涉及到这里的一些内容。 所以,希望下边的这些总结能够对一些学习java或求职的朋友有些许帮助。 1、 关于java类中的缺省的构造器

如果一个java类没有显式定义没有参数的构造器,将有一个默认缺省的构造器。如果定义了一个有参数的构造器,那么原来的缺省的构造器将不在有效。

public class A{ }

此时如果用 new A(); java编译器将使用缺省的构造器。 public class A{ public A(int i){

} }

如果此时用 new A(); 将产生一个编译错误,因为此时显式定义了,一个有参数的构造器。 2、Java中的类名与文件名

1、在一个java文件中可以有多于一个类定义(更常见于某些组件的监听器类),但只能有一个public class定义,且与文件同名。

2、如果一个java源文件中没有public类,那么每个类的名字没特殊规则,即不必与文件同名。 3、在编译后产生的class文件中,仍旧是多个单独分开的class文件。 3、import关键字

1、import语句必须定义在所有的class定义之前。

2、import语句只是为编译器指明了一个路径,并不像C或C++中的#include,所以用import .*并不影响性能。

4、Java中的几个特殊关键字

Java中的关键字许多大家都比较熟悉,而有几个就不是很常用,如: 1、goto和const是保留关键字,在java中没使用 2、strictfp和volatile不常用; sizeof、zhen不是关键字。 3、true,false,null不是严格意义上的关键字,而是literals。 5、java方法中的传递值参

在Java方法中传递参数,对于基本类型来讲传递的是值参数,相当于建立的一个参数的拷贝,不影响原来变量的值。

在引用方法中可以改变传递对象的内容,但对象引用(像A@5d87b2)从来不会改变。

public class tt{

public static void main (String args[]){ A aa = new A(); aa.num =5; tt t = new tt();

System.out.println(\"11 aa=\"+aa + \"num=\"+aa.num); t.test(aa);

System.out.println(\"22 aa=\"+aa + \"num=\"+aa.num); }

void test(A a){

A ab = new A(); a = ab;

System.out.println(\"33 ab=\"+ab + \"num=\"+ab.num); } } class A{ int num; }

6、变量初始化

java中的变量在使用之前必须被初始化,当创建一个对象的时候一些类的变量会自动初始化并赋予缺省值。 数字类赋值0;char类型赋值'u0000'; boolean类型赋值false;引用对象赋值null;

注意的是在方法之外的类变量的值是自动赋初始值,而方法内的局部变量必须手工初始化。

class AA{ int num; void test(){ int j;

j =5;//没有这一行则编译不会通过。 j = j+num; } }

7、switch语句

这个点经常在求职笔试题目中出现。default放在最上边编译没问题;碰到符合分支的,如果没有break会一直向下运行。

public class tt{

public static void main (String args[]){ tt t = new tt();

t.test(2);//可改变成3运行一下看一下结果 }

void test(int i){ switch (i){ default:

System.out.println(\"default\"); case 1:

System.out.println(\"111\"); break; case 2:

System.out.println(\"222\"); break; }

} }

8、关于java中的label使用

? break [label] ? continue[lbele]

? lable: statement; //这里的statement必须是一个loop循环 public class tt{

public static void main (String args[]){ tt t = new tt(); t.test(); }

void test(){

System.out.println(\"0000\"); lb1:for (int i=0;i<10;i++){ lb2:for (int j=0; j<2; j++){ if (i==2) continue lb1;

System.out.println(\"i=\"+i +\" j=\"+j); } }

System.out.println(\"111111\"); } }

9、类型转换校正 class Employee |

class Manager

向上校正,总是允许的,Manager直接使用父类Employee的方法。

向下校正,必须用instanceof检验,才能将一个Employee转换为Manager对象。

public void test(Employee e){ if (e instanceof Manager){ Manager m = (Mnager)e; ... } }

10、方法重载(overloading)、方法覆盖(overriding)

方法重载(overloading)一定要求名字相同,参数不同,返回类型可以相同也可以不同

class A{

void test(int i){ }

}

class AA extends A{ int test(int i, int j){ return 5; } }

注:方法覆盖(overriding)要求名字,参数,返回类型全部必须相同,访问控制符可以不同,但必须大过父类的。因为如果名字和参数都已经相同了则一定要求返回类型相同,否则认为这是一个新的方法了,名字就必须不同了。

class A{

void test(int i){ } }

class AA extends A{

public void test(int i){//若是换成private则编译不通过。 } }

注:关于覆盖方法抛出异常的问题。如A是父类,B是继承A的子类。B中的方法meth()去覆盖父类A的此方法时,B中不能throws出新的异常,只能是父类抛出的异常或其子集。更甚至可以不抛出异常。 11、关于类的构造器重载问题

class A{

public A(int i){ } }

class AA extends A{ public AA(){

int i = 5; // 这里出错,没有父构造器 } }

由于父类A自定义了构造器,所以缺省的构造器就丢失了,当子类的构造器自动试图调用父类没参数的构造器时却没有,所以会编译出错。 12、关于static关键字总结:

1、不能在static修饰的方法中引用this变量,只能引用一些静态变量或方法,或new新的对象(可以定义局部变量)。

简言之,静态方法或块中,只能引用静态的方法或变量。

2、类中的成员变量(static修饰)有缺省值,而类的定义的方法中的局部变量没有缺省值。

3、在类的构造器中,可以引用任何的静态或非静态的变量和方法,可以在非static方法中调用static方法。 4、static{}块中的代码在类装载中仅执行一次。

5、在7-7,A static method cannot be overridden but can be hidden. 不理解。 6、不能在无论非static方法中或static方法中定义static变量。 13、关于final关键字

1、不能继承final修饰的类,不能覆盖final修饰的方法。 2、final修饰的变量,若没赋值,必须在构造器中赋初始值。

class A{ final int j; public A(){

j = 9;//若没有此行,则编译不通过。 } }

3、final类型的方法参数可定义,但不能改变。

class A{

void m(final int i){ //这一行的声明i为一个final没问题。 i ++ ; //但在这里面,i的值不能再被改变。 } }

14、Interface接口关键字 1、接口中的变量 1、必须初始化其值。

2、默认修饰符为public+static+final,其他的修饰符不允许。 2、接口中的方法

1、默认为public+abstract 2、其它修饰符

static,private,protected,final,synchronized,native均不能有。 interface A{ void s();

}

class AA implements A{

void s(){ //编译器在这里提示由于接口中的方法s()修饰符默认是public, //而这里的s()默认是protected,小于public所以不允许。 } }

15、abstract抽象关键字

abstract class A{ private int i; private void m();{} }

抽象类中可以有私有的变量和私有属性,而接口就不行(原因如上),

这是因为java是按实例虚拟调用的,在生成某一个具体的对象可以有私有的属性或方法的。

abstract class A{ private int i; private void m(){};

public abstract void n();//若是private则编译不通过。 }

抽象类中的抽象方法是让其他类继承的,如果本身都是私有的 16、集合类型

以有无顺序,允许不允许重复区分

Collections: 一组对象,无序集合,允许重复 Set:无序集合,不允许重复 List:有序集合,允许重复

注意:在JDK1.1中定义的集合类型,都是线程安全的,所以都是“重量级”的。像HashTable,Vector 而在java2中定义的一些新的集合类型如HashMap, ArrayList不是线程安全的,是“轻量级”的,但速度快,性能好。这一点在许多公司面试试题都见过。 17、布局管理器

FlowLayout,BorderLayout,GridLayout,CardLayout

关于Panel和Frame默认的Layout常在一些公司的面试试题中出现。 1、Panel和Applet类默认的布局管理器是FlowLayout 一个一个的加上去

2、Frame和window类默认的布局管理器是BorderLayout 按东南西北加入 3、xyLayout是Borland公司开发的布局管理器。 18、面试试题中Applet部分 1、使用代码

2、可以覆盖的方法init(),start(),stop(),destory(),paint(g) 19、面试试题中线程部分

1、基本实现方式两中,继承Thread类和实现Runnable接口 2、必须实现父类或接口中的run()方法。 3、有关线程方法,start()启动线程。

join()指在调用这个线程的方法或进程中,必须等待此线程运行结束才能继续其他进程。 4、线程中的同步synchronized,注意死锁。 20、对象串行化

1、仅仅对象类型的数据可以串行化。 2、标记为transient的数据不可以串行化。

存储一个对象到某种永久性存储叫persistence,如存储到磁盘、磁带或别的机器的内存中。

java.io.Serializable接口没有定义方法要实现,仅仅是一个标记暗示实现了这个接口的类可以被考虑串行化。没有实现这个接口的对象不能保存或存储它们的状态。

当一个对象被串行化的时候,仅仅数据被保留,而方法和构造器不是串行化的部分。

一些对象类是不能串行化的因为他们代表的数据是经常变化的。如java.io.FileInputSream和java.langThread。如果串行化的对象包含了不可串行化的对象,整个串行化动作会失败,并抛出NotSerializableException。 21、java中的网络通讯

一般的TCP/IP网络数据通信主要可分2种,TCP和UDP

TCP:TCP是面向连接的通信协议,就像打电话,先要拨通建立连接,传送的数据不会丢失。

java提供了ServerSocket和socket类。在server端,建立一个serverSocket,并指定端口,并侦听连接。

服务器端代码

ServerSocket sc=new ServerSocket(1111); Socket socket1= sc.accept();

DataInputStream s_in = new DataInputStream(socket1.getInputStream());

客户端代码

Socket socket2 = new Socket(\"192.168.1.1\

UDP:UDP非面向连接,就像写信,将传输的数据包成一个分组,可能有数据丢失 服务器端代码

DatagramSocket server = new DatagramSocket(1234);

DatagramPacket in_packet =new DatagramPacket(in_buf,2000); server.recieve(in_packet);

客户端代码

DatagramSocket client= new DatagramSocket(1235); DatagramPacket out_packet=

new DatagramPacket (out_buf,100,\"192.168.1.1\ client.send(outPacket);

22、String对象

一般讲来创建的两个对象如果用==来比较肯定是不等的,因为他们的引用地址是不同的,而==是对于对象来讲是比较对象地址的。但对于String对象来讲是一个例外,两个String对象如果值相同,==比较也是相同的。我想这可能与Sun公司对String对象定义有关。

public class tt{

public static void main (String args[]){ tt t = new tt(); t.test(2); }

void test(int i){ String s1 = \"123\"; String s2 = \"123\"; if (s1==s2)

System.out.println(\"111111\"); else

System.out.println(\"2222222\"); } }

结果输出:111111

Java中利用通讯API编写短信软件

一、 概述

随着手机的逐渐普及,它的主要业务之一“短信”的使用量也水涨船高。但使用手机发短信还有一些不方便的地方,如输入汉字慢、功能有限、手机的存储容量有限等。因此,近几年开始兴起使用电脑向手机发送短信。使用电脑发送短信的方法很多,如通过126、新浪等短信平台通过注册自己的手机号,就可以通过电脑发短信了。但这样做有一些不足,如发短信时电脑必须联入Internet,而且一般使用电脑发短信的费用要比直接使用手机发短信的费用高一些。

当然,还有其它方法发短信。如象126那样租网通或移动的短信服务器,然后通过短信服务器发送短信。这种方式虽然很直接,但是价格昂贵,不是一般人可以承受的(只有象126、新浪这样的服务网站才能用得起)。

最省钱的方法就是到网上去找一个可以免费发短信的软件,我以前使用过一个叫“灵犀机器人”的软件,它们可以有限地免费发送短信,但好象现在也都收费了。这种软件现在越来越少了。

那么是否有折衷的方法,使发短信的费用和手机一样,而且又可以象电脑一样方便地输入、保存、修改和查询短信呢?答案是肯定的,那就是通过数据线将手机和电脑连在一起,使用电脑控制手机发短信。而且这样做电脑无需联入Internet。

二、 如何通过数据线控制手机发短信

一般手机的数据线可以通过COM口或USB口和计算机进行通讯。在本文中我们采用带有COM口的数据线,因为控制COM口比控制USB口更容易、更简单。通过Java和COM口进行通讯有很多方法,可以在Java中直接调用系统API,也可以采用第三方的Java库(这些库在底层也是通过调用系统API实现的)。在本文中我们采用第二种方法,也就是通过第三方的Java库来和COM口进行通讯。在网上这种库很多,在本文中介绍了如何使用Sun的Java通讯API和手机进行通讯,可以在Sun的官方网站下载Java通讯API库 。

三、 如何安装Sun的Java通讯API

安装Java通讯API可分为以下几步:

1. 将下载后的压缩文件zip压缩包解压,假设解压目录为C:commapi。并且保证你的机器中已经安装了Java开发包,假设Java开发包安装在了C盘的C:jdk1.5中。

2. 使用如下命令将win32com.dll复制到C:jdk1.5in中。

copy c:commapiwin32com.dll c:jdk1.5in

3.使用如下命令将comm.jar复制到c:jdk1.5lib目录中。

copy c:commapicomm.jar c:jdk1.5lib

4. 使用如下命令将Javax.comm.properties复制到c:jdk`1.5lib中。

copy c:commapiJavax.comm.properties c:jdk1.5lib

这个文件必须被安装在这,否则系统无法发现COM口。

5. 将comm.jar加入到classpath中

Java和J2EE运行环境的搭建

很多人不能够很好的进行Java编程,原因就在于对Java运行环境的不了解或是了解得不够透彻。如果连一个普通的Java程序运行环境都搭建不好。就更不要说理解J2EE的运行环境搭建了。故本文首先介绍如何搭建普通Java程序的运行环境,再介绍如何在这个基础上进一步搭建J2EE运行环境。

一、什么是JDK?

学Java的人都应该知道SUN公司的Java 技术平台按其应用环境的不同有三个非常著名的版本,他们是J2SE(用于普通桌面应用程序的开发),J2EE(用于企业级应用程序的开发)和J2ME(用于移动设备及其他消费类电子产品的应用程序开发),SUN公司为这三个版本分别提供了相应的开发工具包(SDK:SoftWare Development Kits),下载的网址在http://www.sun.com/downloads,不过可能因为全世界太多人登录的原故,网页经常出现打不开的现象,其实大家在国内一些常用的资料下载网站同样可以DOWN到这些工具包的。在此不一一列举了。顺便提一下J2SE和J2EE目前最新的SDK版本是: ● J2SE 5.0 JDK ● J2EE 1.4 SDK

值得一提的是我们通常所说的JDK工具包指的是J2SE的SDK。目前一般学习者用得最多的也就是这个工具包了。大家还要注意一点,SUN公司为不同的操作系统提供了不同的JDK文件,而且这些文件又有脱机版(OFFLINE)与在线安装版(ONLINE)之分,所以在下载的时候要注意选择正确的文件。

个工具包里到底有些什么东东呢?其实这里面包括了Java程序的开发工具(JavaC命令等)、运行环境(Java命令等)和核心类包。可想而知要想运行Java程序。就必须安装好JDK工具包。 二、如何安装JDK

当我们从网络上DOWN下J2SE 5.0 JDK以后(是一个可执行文件,文件名叫做

jdk-1_5_0-windows-i586.exe,当然这个名字会因为对应操作系统的不同而有所区别的,我使用的操作系统就是WINDOWS,大家发现了吗?),双击他就开始安装了。需要注意的就是选择安装路径的问题,通常我们将它安装在C盘根目录下(这也是安装程序默认的路径),其他的工作就是一个接一个地按NEXT啦。 三、搭建运行和开发环境

是不是当我们装完JDK以后就可以编写代码,准备编译运行了呢?别忙。大家还是跟着我一起检查一下吧:

1、 点击操作系统桌面上左下角的„开始‟菜单,选择„运行‟,然后在打开对话框里输入CMD,看到了吧,我们进入了命令提示符窗口,我们爱叫他DOS界面。

2、现在大家在窗口里应该看到提示符了吧,通常会是这样:C:Documents and SettingsAdministrator> 3、下面让我们在提示符后面敲上这样一个命令:Java,出现了这样的提示了吗? Usage: Java [-options] class [args...] (to execute a class)

or Java [-options] -jar jarfile [args...] (to execute a jar file) ……

这是Java命令的帮助信息,如果有,那么成功一半了。

4、接下来,继续试一下:在命令提示符处敲:JavaC。同样也出现了JavaC的命令帮助提示了吗?我想应该没有吧。你看到的也许会是这样: „Javac‟不是内部或外部命令,也不是可运行的程序或批处理文件。 为什么出现这样的情况呢?

这是因为我们的操作系统在执行一个命令时,首先会到当前目录下去查找这个命令文件。如果在当前目录下找不到,他就会按照系统变量PATH所指示的多条路径里去搜索,直到找到为止。如果在这两个地方都找不到他就会报上面大家看到的错误。

在C:Documents and SettingsAdministrator这个路径下我们当然找不到JavaC命令啦。我们的JDK不是安装在C盘根目录下吗?而我们的JavaC、Java命令则在JDK目录下的BIN文件夹里,这个夹子里还有许多其他宝贝命令。如下图所示:

怎样才能让操作系统找到JavaC命令呢?很简单!我们需要修改一下系统变量PATH,这样就不用每次要运行这个命令时都得跑到C:j2sdk1.4.2_02bin这个路径下面去了。怎样修改PATH,我们在第四个专题里来介绍。 5、当我们在PATH变量里加了一条路径:C:j2sdk1.4.2_02bin以后,再到命令提 示符状态下输入JavaC,就会出现帮助提示了。这就说明我们可以开始写Java程序了。

6、让我们写一个Hello.Java测试一下吧,我在E:LESSON1这个文件夹下创建 v1 了一个文本文件,输入如下一段代码,并且将之保存为Hello.Java。 public class Hello {

public static void main(String args[]) {

System.out.println(\"Hello World!\"); } }

7、好现在我们又回到命令提示符状态下。在提示符处输入:JavaC Hello.Java,命令又出错了。为什么?因为文件是建在E:LESSON1下面,而我们的当前目录却不是它。

在提示符处敲入:„E:‟,然后再敲:„cd lesson1‟,进入Java文件所在的那个目录后,现在再敲JavaC Hello.Java,文件成功编译。

注意成功编译后会在当前目录下生出一个名叫:Hello.class的字节码文件。但是屏幕上没有任何提示。 8、再试着运行一下„Java Hello„这个命令,可以运行吗?当然不行。为什么,因为我们的字节码文件是在Java虚拟机里运行的,所有关于虚拟机要使用的字节码文件的路径必须在一个叫做CLASSPATH的操作系统变量里找得到。否则我们的虚拟机就无法找到这个字节码文件,从而也就无从执行了。

9、怎么办?先运行如下命令:set classpath=%classpath%;E:lesson1,然后再运行 Java Hello 这个命令。屏幕上终于出现了亲切的问候:Hello world! 不过奇怪的事情又发生了。

当我们重新启动一个命令提示符窗口再运行这个Java文件时,又无法执行了,屏幕提示:Exception in thread \"main\" Java.lang.NoClassDefFoundError: Hello。还是老问题,虚拟机又找不到字节码文件了。 为什么呢?其实我们在DOS窗口中设置的系统变量只对当前窗口有效。要想让我们的变量设置对任何一个DOS窗口都有效,还得到桌面上去做。我们仍然将在第四个专题里讲述CLASSPATH这个Java环境变量的设置。 四、PATH系统变量与CLASSPATH环境变量的设置

为什么需要设置PATH和CLASSPATH变量我们在前面的专题已经介绍过了。下面我们讲一下具体如何设置: 1、右键单击我的电脑,选„属性‟菜单,在弹出的对话框里选择„高级„选项卡。然后在高级选项卡页按下„环境变量‟按钮。

2、在弹出的环境变量窗口里我们将会看到它分为两个部分。一部分是谁谁用户的变量,如:Administrator的用户变量。一部分是系统变量。通常情况下我们在命令提示符下能够使用的变量数目是用户变量+系统变量数目之和。

那我们不管用户变量。直接到系统变量格里去寻找PATH变量吧。通常情况下系统装好后PATH变量在这里是早就存在了的。但是CLASSPATH变量则没有。

3、找到PATH变量后,双击这个变量名称后,将会弹出编辑系统变量窗口。将光标停到变量值对话框的最后,然后加上„;C:j2sdk1.4.2_02bin ‟。注意分号后的路径就是Java和JavaC命令所在的路径。

4、找不到CLASSPATH变量该怎么办呢?很简单。按下系统变量框下的新建按钮。然后在弹出的新建系统变量对话框里输入你要加的变量名称:CLASSPATH,在变量值对话框里输入你要运行的字节码文件所在的路径。 大家在以后的学习中会发现,只要是虚拟机运行所需的字节码文件(即类文件),包括SUN公司提供给我们的类。都需要将这些文件所在的路径放到CLASSPATH下。否则,程序在编译过程中会经常找不着所需要的类包。那可是很头疼的事。

比如说:JDK安装目录下的LIB目录下就有许多*.jar文件。当我们的程序要使用到这些压缩文件里的类时,就需要把这些文件所在的路径加到CLASSPATH里,比如说:C:j2sdk1.4.2_02libdt.jar。 srI2) 注意添加*.jar包和直接添加*.class文件的路径是有一点小小区别的,前者要包含JAR包的名字。而后者只需文件路径。 五、J2EE运行环境的搭建 :

开发企业级的应用程序需要搭建好J2EE的运行环境。其实也就是到SUN公司的网站上去DOWN下J2EE 1.4 SDK开发工具包。然后双击安装文件,如果你下载的版本与我的一样。那么这个安装文件就会是这个名字:j2eesdk-1_4-dr-windows-eval.exe。同样的我们也将J2EE SDK安装在C盘根目录下。

需要特别提醒大家的是:J2EE运行环境的搭建是以J2SE运行环境的搭建为基础的。其实想也想得到为什么。如果没有JDK,哪里来的编译和运行命令呢(Java和Javac)。安装完J2EE 1.4 SDK包后,具体的设置与测试步骤如下:

1、首先右往PATH变量里添加J2EE SDK的BIN目录。如:C:j2sdkee1.3.1bin。如何往里面添加,前面已经讲过。

2、 然后新建两个变量:一个是Java_HOME,变量值为:JDK的安装目录。另一个是J2EE_HOME,变量值为J2EE SDK的安装目录。

3、 最后往CLASSPATH变量里添加一个关键的JAR包。它就是J2EE.JAR包。比如我添加的就是:C:j2sdkee1.3.1libj2ee.jar。

4、 所有的工作做完以后。大家可以通过以下方式验证一下我们的J2EE环境是否已经搭建成功。在命令提示符状态下输入命令:J2EE -Verbose。如果屏幕的最下面看到了这样一句话J2EE server startup complete.那就表示J2EE服务器成功启动了。在我们的J2EE程序要布署和运行的过程中。服务器将一直启动着。

另外提一下,如果你需要停止J2EE服务器,必须再开一个命令窗口,并运行如下命令:J2EE ?STOP。成功运行后,将会有提示语句。再去看看启动服务器的那个窗口,你将可以看到提示符了。

5、 这样做了还不够,我们还需要到网页里去测试一下服务器默认页面是否能够正常显示,这样才能保证我们能够进WEB程序的开发。双击IE浏览器的图标,在地址栏里输入:http://localhost:8000,如果你能看到以下窗口中的内容,那就说明你的J2EE环境已经搭建成功。需要说明一点,在localhost:后的是J2EE服务器提供的WEB服务端口号。

需要提醒大家的是:当你打开网页之前,确认你的J2EE服务器是启动着的。如果你机器上没有安装网卡,或是网卡安装不正确,也会导致无法打开J2EE服务器默认页面。 六、在JCreater中开发程序需做的配置

大多数初学者使用的的集成开发环境都是Jcreator。这是一个很适合学习者使用的开发工具。但是使用时需注意以下几点:

1、最好是先装好J2SE SDK和J2EE SDK之后再去安装Jcreator。这样关于JDK的设置Jcreator会自动完成。

2、 那如果不幸先装了Jcreator,后装的JDK也不要紧。可以这样做,完成配置:选择‟Configure‟菜单。选择Options菜单。

然后选中JDK Profiles。点击NEW按钮,弹出如下对话框 选中J2sdk1.4.2_02目录。然后点击确定按钮。 接下来将会弹出下面的对话框:

我们会发现这个目录下及子目录下几乎所有的JAR包都在窗口里显示出来了。这样就不怕Java虚拟机找不到所需的类了。再点OK吧。

回到OPTIONS窗口继续点OK就回到Jcreator的主界面了。

3、 上面的工作做完以后我们进行普通Java程序的开发是没有问题了。不过要进行企业级开发。还得加几个JAR包。重新打开上面看到的Options窗口。选择JDK Profiles,选中J2SDK1.4.2_02,再点击EDIT按钮。 将会弹出PROFILES窗口,点击ADD按钮。选择ADD ARCHIVE选项。在弹出的对话框里选择J2EE SDK的安装路径,并且进入LIB目录。选中所有的JAR文件。 点击打开按钮。OK两次后回到Jcreator主界面下。 做完这件事后我们可以在JCREATOR中写J2EE代码了。

到这里,Java和J2EE运行环境的搭建就介绍完了。大家开始加油编写代码吧。告诉大家学习Java和J2EE唯一的办法就是敲代码,唯有抄代码抄出心得以后,你才可以写出自己的漂亮的程序。

构建有效的系统模型

引言

长期以来,可视建模被视为软件开发的一项主要最佳实践。通过关系图,设计人员和分析人员能够更方便而有效地向各种受众呈现复杂信息。不幸的是,很多模型的构建工作差强人意、缺乏组织性或使用率不高。为了尽可能从可视模型表示获得最大好处,不仅应该考虑模型的内容,还要考虑信息的表示。创建有效的系统模型时,需要关注三个主要概念:关系图形式 的选择、关系图围绕共同 主题 的组织以及侧重名为轴心内容 的信息具体特征的视图的创建。 模型形式

有两种相关的模型形式:表示形式和组织形式。软件开发中的常见表示形式是 UML,可详细说明由 13 种关系图类型组成的集合的具体概念和语法,每个类型都分别针对从需求到部署的特定软件系统开发方面。这包括结构关系图(如类、对象和部署)和行为关系图(如序列、活动和状态)。此类关系图集合的内容非常多,这意味着您必须全面地了解每种形式,仔细考虑目标受众,并花时间创建一致且具有内聚性的关系图集合,以传递模型的预期意图。例如,系统设计人员对系统的逻辑和物理方面感兴趣,因此最有用的形式就是类和序列关系图,而不是用例和活动关系图。相反,系统分析人员对用例关系图中描述的概念感兴趣,而对构造和部署的细节不太感兴趣。 UML 语法可强制规定特定的建模关系。例如,消息关系仅能出现在对象的两个实例间。

除了 UML 外,还经常使用其他一些建模形式用于软件建模,包括美国国防部体系结构框架(Department of Defense Architecture Framework,DODAF)、Open Group 体系结构框架(The Open Group Architecture Framework,TOGAF)和 Zachman 框架。(有关 Zachman 框架的更多信息,请参见参考资料。)另外还可以使用不同的语言,如集成计算机辅助制造(Integrated Computer-Aided Manufacturing,ICAM)定义语言、实体关系数据模型和使用系统建模语言(Systems Modeling Language,SysML)捕获的系统模型。无论所使用的建模形式或语言如何,都必须采用一致的方式描述所涉及的系统。

可以将模型的组织形式作为一组视角加以捕获(请参见侧栏)。视角定义为模型视图的集合,使用一组关系图、文档和其他相关构件进行表示。可以为了满足对模型内容感兴趣的特定涉众创建每个视图(请参见图 1)。

图 1. 应用程序模型视角

可查看此图像的放大版本。

软件应用程序必须满足不同的涉众需求,因此描述这些系统的模型也一定具有复杂性。例如,业务涉众对需求 (Requirements) 视角感兴趣,可以将此视角用于组织用例关系图、活动关系图和其他关于系统功能的信息。软件系统存在很多可能的视角,包括 Philippe Kruchten 的经典 4+1 视图(有关更多信息,请参见参考资料部分)以及侧重环境注意事项、维护和自动化测试的视角。表 1 描述了对任何软件系统模型都应该有用的一组视角。

表 1. 常见的有用视角 视角 需求 部署 环境 代码

视角元素

用例、补充需求、业务规则 部署环境与打包

服务器布设图、网络图、系统分布 组件描述、通信/消息传递、物理打包

用法指导原则

包含涉众需求、系统功能以及需求的描述

包含用于说明部署到开发环境、测试环境、用户接受环境和生产环境的操作的系统部署视图以及每个部署的详细配置信息

软件的工作环境,包括对各个系统组件的分配情况

包含所有基于代码的开发的实现详细信息,包括文件系统结构、构件版本依赖关系以及配置参数

详细说明应用程序的逻辑视图,包括数据、行为和结构(如体系结构层次和模型) 保留用于说明系统的操作细节,如报告、监视、日志记录和恢复过程 支持所有测试,包括单元测试、集成测试、系统测试和回归测试

逻系统行为、系统结构、数据模型、体系结构辑 层次、设计模式 维护 测试

监视、警报、报告/日志记录、恢复 单元测试用例、自动化

模型主题

确定了模型的相应形式后,需要根据每个系统体系结构区域的主题对信息进行组织。例如,所有软件系统的一个关键方面是内部依赖关系的组织;表示这种关系的一个方法是采用分层体系结构。表示此区域的模型视图集合的主题是依赖关系管理。因此,模型主题由系统的本质所决定,包括系统用途和目标。模型中视角的内容是围绕特定的主题收集的,类似于表 2 中的内容。

表 2. 应用程序模型主题

主题 分层 业务类别 集成 工作流 规则 环境

构建、打包与交付

描述 依赖关系管理 稳定的业务操作和流程

子系统和组件间的适配器、连接器和接口

系统操作与异常控制 对系统行为的约束 操作系统、资源和配置 系统组件、物理交付媒介以及机制

示例 数据访问层 合同谈判 第三方关系数据库

规则引擎 数据验证 服务器进程分配

构建文件(.zip 和 .tar 文件、FTP 交付与 HTTP 下载)

为了进行演示,让我们以一个特定的视角及该视角中的主题为例。例如,假定所考虑的系统是管道修复公司的调度应用程序。该公司需要有效地分配每辆车和每个技术人员,从而使技术人员在前后工作现场之间用在路上的时间尽可能少。一系列涉众对此系统感兴趣,包括业务所有者、系统开发人员、技术人员、系统管理员、数据管理人员、需求工程师、测试人员和架构师。具体的视角可满足不同涉众的需求。例如,“用例”视角允许需求工程师和业务所有者讨论系统功能的特征。“逻辑”视角则侧重说明结构和行为方面的情况。结构方案可能包含一系列主题,其中一个就是资源调度要点。在本例中,所感兴趣的资源是技术人员、车辆以及需要进行调度的工作。图 2 显示了一个这样的结构视图。

图 2. 工作和调度管理

图 2 还说明了关系图如何使用轴心内容(在关系图轴心内容部分讨论)表示模型信息。此处的轴心内容是

JobSchedule 组件的结构关系。具体来说,查看者将会注意到 ScheduleManager,因为其颜色不同,而且位于

关系图的上部居中位置。请注意关系图中没有显示外部信息,如调试日志记录等。这可确保仅仅传递单个信息——关系图轴心内容所代表的信息。

除了结构关系图外,还可以通过其他几个关系图说明行为,如序列关系图和主题关系图(请参见图 3)。

图 3. 工作状态图

所有这些关系图的主题都是“资源调度”,所以会在模型中进行分组。通过按主题对模型视图进行分组,可以确保模型提供一组针对特定查看者(如涉众)的有组织视图,而且能够代表系统描述的重点部分。

关系图轴心内容

最后,必须考虑每个特定关系图的内容。为了确保每个关系图有效地表示其信息,需要确保关系图内容基于单一的特定信息。轴心内容提供关系图元素焦点,可确保仅在特定的关系图中包含相关的信息。例如,在图 3 所示的 Job 的状态关系图中,关系图仅仅关注 Job 及其状态转换。如果包括了其他对象,关系图将在其重点及其要传达的信息方面就会变得模糊。

此处要记住的最重要一点是:使用关系图向查看者传达模型所包含的内容。其他的都是用于帮助快速找到提及的关系图的组织结构。因此,如果查看者对关系图信息感到迷惑不解,则可能因为其中包含的信息太多,关系图达到预期影响的目的就可能无法实现。

创建复杂系统关系图的人员会有一种奇怪的趋势,习惯不断向关系图中添加越来越多的信息,以致于会让受众感到信息容量过多。或许他们希望创建涵盖系统的所有有意义部分的单一视图。不过,通过在一个可视图像中提供这么多信息,会让核心信息被细节所淹没。我遇到过很多这样的情况,但我想说在从事科研工作早期所遇到的一种情况。我当时在参加一位知名研究人员主持的研讨会,他在会上说明自己在细胞信号传递途径方面的成果。他的演讲的开始部分非常好,使用了几张概述性的幻灯片,每张幻灯片都侧重于单个信息点——每张幻灯片都具有清楚的轴心内容。然后他将有关四个复杂图表的数据全部挤到了单张幻灯片中。任何离屏幕两英尺远的人都无法阅读其中的内容,

甚至他自己在区分每个坐标标签时都出现了错误。无数的数据行都以单色显示,似乎是随意排列在每个图表上,数据中的小数点与污迹都无法区分了。不管怎样,这位受人尊敬的科学家接下来用了 20 分钟时间解释这单张幻灯片中的所示的数据。我留意了一下房间中的其他人,几乎所有人(包括我自己)都感到迷惑不解,大部分都完全失去了兴趣。

这个例子的要点是,很容易在给出了大量详细信息时让人产生困惑。如果演讲者直接将四个图表分为独立的幻灯片,则每个人都能够更好地了解其中的细节。而且,这将帮助对屏幕显示进行分离,从而使其一次仅涉及一个要点——清楚的核心内容。让听众分别看四个图表将更容易跟上演讲者的思路,而通过一个总结幻灯片又能将四个图表的内容方便地整合在一起。

考虑每个关系图的轴心内容时,首先要考虑整个表示(或模型)。所描述的整个系统是什么?最好采用哪种方法进行表示,以便每个组件提供足够的细节?可以忽略哪些内容,以便查看者更好地重点关注重要方面?通过这些问题,可以很好地选择轴心内容点。对于形式和主题,可以选择很多可能的关系图轴心内容(请参见表 3)。

表 3. 关系图轴心内容类别 轴心内容 控制点 框架使用情

况 风险 接口 性能 结构 行为

集中业务逻辑点 框架元素实现和集成 高复杂性、耦合与变更 子系统与组件间的接口的实现 关注处理瓶颈、资源利用率和限制

系统的结构方面,如包含层次机构、状态表和组件关系(依赖关系)

描述

示例

Enterprise JavaBeans (EJB) 会话对象 事务管理和安全性 体系结构相关的用例实现

体系结构机制实现,如消息传递、安全性和审核 商业化的现成集成适配器 包含用例实现的协作关系图 Web 服务 类/组件关系图

体系结构 体系结构相关的用例或系统组件 功能分配 需求与设计间的可跟踪性

序列关系图 系统的行为方面,如消息传递、对象创建/销毁、方法调用、广播/侦听器

在 UML 中,每个关系图侧重特定的系统方面,如类关系图用于捕获结构信息。不过,特定关系图类型中应该只有一个信息焦点(即轴心内容)。定义糟糕的轴心内容可能会让关系图要传递的信息含混不清。

总结

创建系统模型在时间和资金方面投入都比较大;让这个重要的资源由于对模型结构错误认识而被滥用,既非常浪费,也会降低效率。模型旨在进行重复利用;根本没有理由让开发团队将宝贵时间浪费在构建复杂而详细的一次性构件上。为了让模型创建和维护方面的成本物有所值,需要确保模型非常有用。

除非系统模型中包含的信息经过了有效的组织,能够进行方便的维护,而且能够让模型受

众快速发现相关信息,否则创建复杂的系统模型几乎没有任何价值。缺乏组织性的模型将很快失去准确性,会变得很难使用(可能这一点更为重要),从而导致最终将其弃用。创建模型需具有一致的形式、围绕可理解的共同主题而且需提供信息关系图的内聚性集合,才能提高此模型的短期和长期价值。只有这样,在可视建模工作上所投入的精力才会带来巨大的好处。

因篇幅问题不能全部显示,请点此查看更多更全内容