有点忧郁

有些犹豫

编码我不喜欢

也不擅长

 

每天都在挣扎

却越陷越深

想摆脱这一切

可是没有摇钱树

 

利禄我所欲也

功名我所欲也

可惜我的梦想

早已生根却无法发芽

 

难道我就要以一个借口

生活是不容易的

荒废时光

白白度过

 

我是中了谁的毒

宁愿没有进入这象牙塔

也许我会做我喜欢的

至少不会这么苦苦维持

 

 

 

posted @ 2011-01-08 19:36 洛可可 阅读(33) 评论(2) 编辑

转自:http://www.blogjava.net/liyingcheng/archive/2007/10/24/155602.html

 

开发环境
    Sun Java 5+ Eclipse 3.2 +MyEclipse 5.0.0. 

    概述 

    本文介绍了使用MyEclipseWeb Service来迅速开发和测试一个HelloWorld Web Service,其中包括: 
    1. 介绍了MyEclipse Web Services的基本概念 
    2. 创建一个MyEclipse Web Services工程 
    3. 创建一个简单的HelloWorld WebService 
    4. 在Web容器中,如Tomcat 5中部署Web Service 
    5. 使用Web Services Explorer来测试部署的Web Services 

    XFire Java SOAP框架概述 
    MyEclipse Web Services是建立在XFire JavaSOAP框架和工具基础上的, XFire是一款开源的JavaSOAP框架。它拥有一个轻量级的信息处理模块,通过STAX来与SOAP信息相结合。提供了一个工作在Web Services下的简单API,支持POJO和schema开发. XFire支持 Web Services standards,Spring 整合, 支持JBI , 支持 JAXB ,XMLBeans,Java 5 和JAX-WS.并支持HTTP, JMS, XMPP, In-memory传输协议. 

    一. 创建WebService工程 

    在MyEclipse 5.0中引入了一个新的工程类型即Web Service工程,该工程扩展了MyEclipseWeb Project来支持额外的Web Service配置,开发和部署.本部分将使用Web Services Project wizard来创建和配置一个新的Web Service Projects Web Service Wizard将完成下列的动作: 
    创建MyEclipse J2EE Web Project 
    在工程中的web.xml文件中配置XFire Servlet 
    创建XFire services.xml配置文件 
    在工程中的构建路径中添加MyEclipse-XFire类库 
    添加一个指定的MyEclipse web project builder到.projects文件,以便部署services.xml文件到它合适的位置.如:<webroot>/WEB-INF/classes/META-INF/xfire/ 

    运行Web Service Project Wizard 
    该向导包括三个页面, Page-1搜集Web Project配置细节, Page-2搜集XFire配置细节, Page-3在新建的构建路径中配置XFire类库 
    1. 执行Web Services ProjectWizard. 
       1). 选择File>New>Other 
       2). 扩展MyEclipse种类按照J2EE工程的种类 
       3). 选择Web ServicesProject然后点击Next,如图所示

 


    Figure-1: New Project Wizard Launcher 
    2. 添加Project Name,点击Next

 


    Figure-2: Page-2, Collecting web configuration details 
    3.在向导的Page-2中添加XFire servlet和service.xml文件的配置信息,按照默认的值即可.

 


    Figure-3: XFire servlet and services.xml configuration
    4.在向导的Page-3中选择类库添加到工程的构建路径中,其中XFire Core Library是需要的,如果要在工程中开发一个客户端应用, XFire HTTP ClientLibraries也是需要的.

 


    Figure-4: Selecting XFire libraries to add to new webservice project buildpath 

    5选择Finish完成Web Service工程的创建过程 
    Figure-5,显示了新创建的HelloWorld WebService工程的组织结构,Web Service 工程和一个标准的MyEclipse Web工程很相似. XFire Web Service配置元素如图红色区域显示:

 


    Figure-5: Web services artifacts of a new web serviceproject 

    二. 创建Web Service-Code-first Strategy 
    在这部分将用MyEclipse Web Service Wizard并通过使用Code-first Strategy来创建一个HelloWorldService示例. 

    1. 执行MyEclipse Web Service Wizard,有两种方法来执行MyEclipse Web Service Wizard 
    方法1.从MyEclipseperspective toolbar中来执行向导 
    在打开的Web Service Wizard上的workbench上来选择新Web Service按钮 
    方法2.从workbenchmenubar执行向导 
    1. 从workbench menubar选择: File>New>Other>MyEclipse>Web Service

 


    Figure-6: Launching Web Service Wizard 

    2. 在Page-1选择HelloWorld 工程并选择Create web service from Javabean 
    3. 选择Next到Page-2

 


    Figure-7: Page-1 of new web service wizard

    4. 填写Web Service的名字HelloWorldService 
    5. 选择Java Source folder或者选择New按钮来新建一个source folder 
    6. 填写Java package或者通过选择Browse按钮来选择一个已经存在的package.也可以选择New按钮来新建一个Java package 
    注意:对Service接口和Service执行的类的默认值是基于所填入Web Service名字来产生的. 
    7. 选择Next来初始化Web Service的创建过程

 


    Figure-8: Page-2 of new web service wizard. 
    该向导产生了IHelloWorldServiceJava接口和HelloWorldServiceImpl Java类.并且在services.xml配置文件中创建了一个<service>实体(如图所示),注意到example(String message)方法在接口类中产生,当Web Service部署后作为一个测试操作.

 


    Figure-9: Newly created HelloWorld interface andimplementation class 

Web Service 服务端服务接口代码

package org.stephencat.ws;
//Generated by MyEclipse

public interface ISampleService {
    
    public String example(String message);
    
}


Web Service 服务端服务实现代码

package org.stephencat.ws;
//Generated by MyEclipse

public class SampleServiceImpl implements ISampleService {
    
    public String example(String message) {
        return message + " This is Xfire !!";
    }
    
}


    
    三. 部署Web Service Project 
    Web Service可以部署在任何MyEclipse支持的J2EE应用服务器上,该部分将演示如何在Tomcat5 Web容器上部署HelloWorld工程. 

    3.1部署HelloWorld Web Service Project 

    Figure-10显示了如何部署HelloWorld应用. 
    1. 从Server Manager中选择Deployer按钮(step-1) 
    2. 在Server Deployments对话框中选择Add to create a new deployment (step-2) 
    3. 在New Deployment对话框中选择HelloWorld工程并选择Exploded Archive选项 
    4. 在New Deployment对话框选择Finish来将HelloWorld在Tomcat5默认的位置中打包为WAR 
    5. 选择OK完成部署

 


    Figure-10: Three-step deployment process 
    新HelloWorld WAR部署将出现在Server Manager视图中Tomcat 5节点下.

 


    Figure-11: Servers Manager View depicting deployedHelloWorld web service project

    四. 启动Tomcat服务器 (或 JBoss 服务器

    五. 使用WebService Explorer测试Web Service 
    MyEclipse提供了一个Web Service Explorer来测试Web Service. 
    1. 在MyEclipse perspective中选择toolbar button来执行Web Service Explorer

 


    Figure-15: Web Services Explorer launch button on workbenchtoolbar 

    2. 选择WSDL模式(Figure-16) 
    3. 在活动面板中键入HelloWorldService WSDL文档的URL

http://localhost:8080/wstest/services/SampleService?WSDL

Web Service Explorer将下载自动产生的WSDL文档,该WSDL文档由XFireframework,并产生一系列的操作能够调用service. 
    4. 在活动面板中选择example操作并在in0域中键入HelloWorld 
    5. 选择Go按钮来调用在HelloWorldService上的example操作,,结果出现在Status面板上

 


    Figure-16: Web Services Explorer testingHelloWorldService 

    六. 创建Java Test客户端 
    XFire提供了一个动态的代理框架,能够读取WSDL文档和创建潜在的消息服务使Java类来执行在Web Service的行为.该部分将为HelloWorldWeb Service写一个Java Web Service客户端 
    6.1增加XFire类库配置 
    为了使example client能够在HelloWorld工程中运行,需要增加XFireHTTP Client类库到工程的构建路径中. 
    1. 在Package Explore视图中右击HelloWorld工程选择Build Path>AddLibrary 
    2. 选择MyEclipse Libraries 
    3. 选择XFire HTTP Client Libraries

 


    Figure-17: Choosing the XFire HTTP Client Libraries 
    4. 选择Finish 
    6.2创建HelloWorldClient类 
    执行Java类向导来创建HelloWorldClient类

 


    Figure-18: HelloWorldClient defined in New Java ClassWizard. 

    Web Service 客户端代码如下:

package org.stephencat.ws;

import org.codehaus.xfire.*;
import org.codehaus.xfire.service.*;
import org.codehaus.xfire.service.binding.*;
import org.codehaus.xfire.client.*;

import java.net.*;

public class SampleClient {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Service srvcModel = new
        ObjectServiceFactory().create(ISampleService.class);
        XFireProxyFactory factory =
           new XFireProxyFactory(XFireFactory.newInstance().getXFire());
        String url =
           "http://localhost:8080/wstest/services/SampleService";
        try {
            ISampleService srvc = (ISampleService)factory.create(srvcModel, url);
           String result = srvc.example("hello world");
           System.out.print(result);
        } catch (MalformedURLException e){
           e.printStackTrace();
        }


    }

}


    该段代码定义了创建一个XFireweb service proxy的过程,该代理支持POJOIHelloWorldService接口 

    右键点击Run As>Java Application或者Debug As>JavaApplication来运行或调试该程序

posted @ 2010-12-16 14:59 洛可可 阅读(53) 评论(0) 编辑

几种开源Java Web容器线程池的实现方法简介——Tomcat(二)

ThreadPool提供的仅仅是线程池的实现,而如何使用线程池也是有很大学问的。让我们看看Tomcat是如何使用ThreadPool的吧。

Tomcat有两种EndPoint,分别是AprEndpoint和PoolTcpEndpoint。前者自己实现了一套线程池(其实这和Tomcat 老版本的方案是相同的,至今Tomcat中还保留着老版本的线程池,PoolTcpEndpoint也有类似的代码,通过“策略”可以选择不同的线程池方案)。我们只关注PoolTcpEndpoint如何使用ThreadPool的。

首先,PoolTcpEndpoint创建了一个ThreadPoolRunnable实例——LeaderFollowerWorkerThread,实际上该实例就是接收(Accept)并处理(Process)用户socket请求。接着将该实例放进ThreadPool中并运行,此时就可以接收用户的请求了。

当有Socket请求时,LeaderFollowerWorkerThread首先获得了Socket实例,注意此时 LeaderFollowerWorkerThread并没有急着处理该Socket,而是在响应Socket消息前,再次将 LeaderFollowerWorkerThread放进ThreadPool中,从而它(当然是另外一个线程了)可以继续处理其他用户的Socket 请求;接着,拥有Socket的LeaderFollowerWorkerThread再来处理该用户的Socket请求。

整个过程与传统的处理用户Socket请求是不同的,也和Tomcat老版本不同。传统的处理方法是:有一个后台运行的监听线程负责统一处理接收(注意只是“接收”)Socket请求,当有新的Socket请求时,将它赋值给一个Worker线程(通常是唤醒该线程),并有后者处理Socket请求,监听线程继续等待其他Socket请求。所以整个过程中有一个从Listener到Worker切换的过程。

而新版本Tomcat很有创造性的使用了另外一种方法,正如前文所描述的,接收和处理某个用户Socket请求的始终是由一个线程全程负责,没有切换到其他线程处理,少了这种线程间的切换是否更有效率呢?我还不能确认。不过这种使用方式确实有别于传统模式,有种耳目一新的感觉。

 

几种开源Java Web容器线程池的实现方法简介——Jetty(三)

除了Tomcat外,Jetty是另外一个重要的Java Web容器,号称“最小的”Web容器,从Jetty的源代码规模可以看出它确实比较小。而且它的ThreadPool的实现也非常简单,整个代码ThreadPool代码只有450行左右,可见小巧之极。

ThreadPool代码位于com.mortbty.thread包中,其中最重要的方法是dispatch()和内部类PoolThread。顾名思义,dispatch方法主要是将Runnable实例派给线程池中的空闲PoolThread,由后者运行Runnable。

还是看看整个过程吧。首先,ThreadPool创建_minThreads个空闲PoolThread,并把它们添加到空闲线程队列中。当需要运行 Runnable时,首先查找是否有空闲的PoolThread,如果有空闲的,这由它处理;如果没有并且PoolThread并没有超过 _maxThreads个时,则创建一个新的PoolThread,并由这个新创建的PoolThread运行Runnable;如果 PoolThread超过了_maxThreads,则一直等待有空闲的PoolThread出现。在PoolThread运行之前,必须把该 PoolThread从空闲线程队列中移走。

再来看看PoolThread的实现吧。和所有的Worker线程一样,用一个while(flag){wait();}循环等待Runnable的到来,当有Runnable被ThreadPool.dispatch()时,该PoolThread就运行Runnable;当运行完成后,再“归还”给空闲线程队列。

Jetty如何使用ThreadPool?整个Jetty只使用了一个ThreadPool实例,具体入口在 org.mortbay.jetty.Server中被实例化的,Connector中也使用Server的ThreadPool处理用户的Socket 请求。Connector是处理用户Socket请求的入口,一个Connector创建_acceptors个Acceptor,由Acceptor处理用户Socket请求时,当有Socket请求时,就创建一个Connection放到线程池中处理,而Acceptor继续处理其他的Socket请求。这是个传统的Listener和Worker处理方式。

 

几种开源Java Web容器线程池的实现方法简介——Resin(四)

在这些Java Web容器中,Resin算得上很特别的,小巧稳定,而且效率很高。在这些Java Web容器中,算它的效率最高了。很多大型的网站中都能找到它的身影。Resin从3.0版本后开始走“特色”的开源路,与MySql很相似——如果用于商业目的,则需要买它的License。但对于个人研究而言,这已经不错了,在网站上可以下载除了涉及License的源代码外其他所有代码。

说Resin特别,还主要是由于它的性能出众,即使在很多企业级应用中也能派上用场。Resin的数据库连接池做的很不错,效率非常高。不过这里我们讨论它的线程池,看看有何特别之处。

Resin的ThreadPool位于com.caucho.util.ThreadPool中,不过这个类的命名有点蹊跷,更恰当的命名是ThreadPoolItem,因为它确实只是一个普通的Thread。那线程调度何管理在哪里呢?也在这个类中,不过都是以静态函数方式提供的,所以这个类起到了两重作用:线程池调度和Worker线程。也由于这种原因,Resin实例中只有一个线程池,不像Tomcat和Jetty可以同时运行多个线程池,不过对于一个系统而言,一个线程池足够了。

和其他线程池实现方式不同的是,Resin采用链表保存线程。如果有请求时,就将Head移走并唤醒该线程;待运行完成后,该线程就变成空闲状态并且被添加到链表的Head部分。另外,每一个线程运行时都要判断当前空闲线程数是否超过_minSpareThreads,如果超过了,该线程就会退出(状态变成Dead),也从链表中删除。

Resin如何使用该ThreadPool?所有需要用线程池的地方,只需调用ThreadPool.Schedule(Runnable)即可。该方法就是一个静态函数,顾名思义,就是将Runnable加到ThreadPool中待运行。

Resin使用的还是传统方法:监听线程(com.caucho.server.port.Port),系统中可以有多个Port实例,前提端口号不同,比如有80和8080端口;另外就是Worker线程,其实就是ThreadPool中的空闲线程。Port本身是一个Thread,在启动时,会在 ThreadPool中运行5个线程——TcpConnection同时等待用户请求,当有用户请求时,其中的一个会处理。其他继续等待。当处理用户请求完成后,还可以重用这些TcpConnection,这与Jetty的有所不同,Jetty是当有用户请求时,才创建连接,处理完成后也不会重用这些连接,效率会稍差一些。

另外Resin有两个后台运行线程:ThreadLauncher和ScheduleThread,前者负责当空闲线程小于最小空闲线程时创建新的线程;而后者则负责运行实际的Runnable。我觉得有的负责,没有必要用一个线程来创建新线程,多此一举。不过ScheduleThread是必须的,因为它就是Worker线程。

June 23rd, 2006

几种开源Java Web容器线程池的实现方法简介——总结(五)

介绍了tomcat、jetty和resin三种Java Web容器的线程池后,按照惯例应该比较它们的优缺点。不过先总结线程池的特点。

线程池作为提高程序处理数据能力的一种方案,应用非常广泛。大量的服务器都或多或少的使用到了线程池技术,不管是用Java还是C++实现,线程池都有如下的特点:

线程池一般有三个重要参数:

1. 最大线程数。在程序运行的任何时候,线程数总数都不会超过这个数。如果请求数量超过最大数时,则会等待其他线程结束后再处理。

2. 最大共享线程数,即最大空闲线程数。如果当前的空闲线程数超过该值,则多余的线程会被杀掉。

3. 最小共享线程数,即最小空闲线程数。如果当前的空闲数小于该值,则一次性创建这个数量的空闲线程,所以它本身也是一个创建线程的步长。

 

线程池有两个概念:

1. Worker线程。工作线程主要是运行执行代码,有两种状态:空闲状态和运行状态。在空闲状态时,类似“休眠”,等待任务;处理运行状态时,表示正在运行任务(Runnable)。

2. 辅助线程。主要负责监控线程池的状态:空闲线程是否超过最大空闲线程数或者小于最小空闲线程数等。如果不满足要求,就调整之。

 

如果按照上述标准去考察这三个容器就会发现:Tomcat实现的线程池是最完备的,Resin次之,而Jetty最为简单。Jetty没有控制空闲线程的数量,可能最后空闲线程数会达到最大线程数,影像性能,毕竟即使是休眠线程也会耗费CPU时钟的。

谈谈Resin的线程池。Resin的实现比Tomcat复杂些。也有上述三个参数,也有两个概念,这与Tomcat相当。但考虑到如何使用ThreadPool时,Resin也要复杂些。

或许由于Resin的ThreadPool是单间模式的,所有使用ThreadPool的线程都是相同设置,比如相同的最大线程数,最大空闲线程数等,在使用它时会多些考虑。比如在控制最大Socket连接数时,com.caucho.server.port.Port还要有自己的一套控制“数量”的机制,而无法使用ThreadPool所特有的控制机制。所以使用起来比Tomcat复杂。

Tomcat使用ThreadPool却很简单。由于Tomcat的ThreadPool可以有不同的实例存在,很方便的定制属于自己的“数量”控制,直接用ThreadPool控制Socket连接数量。所以代码也比较清爽。

如果要使用线程池,那就用Tomcat的ThreadPool吧。

posted @ 2010-12-16 14:54 洛可可 阅读(326) 评论(0) 编辑

      目前市场上常用的开源Java Web容器有Tomcat、Resin和Jetty。其中Resin从V3.0后需要购买才能用于商业目的,而其他两种则是纯开源的。可以分别从他们的网站上下载最新的二进制包和源代码。

      作为Web容器,需要承受较高的访问量,能够同时响应不同用户的请求,能够在恶劣环境下保持较高的稳定性和健壮性。在HTTP服务器领域,ApacheHTTPD的效率是最高的,也是最为稳定的,但它只能处理静态页面的请求,如果需要支持动态页面请求,则必须安装相应的插件,比如mod_perl可以处理Perl脚本,mod_python可以处理Python脚本。

      上面介绍的三中Web容器,都是使用Java编写的HTTP服务器,当然他们都可以嵌到Apache中使用,也可以独立使用。分析它们处理客户请求的方法有助于了解Java多线程和线程池的实现方法,为设计强大的多线程服务器打好基础。

      Tomcat是使用最广的Java Web容器,功能强大,可扩展性强。最新版本的Tomcat(5.5.17)为了提高响应速度和效率,使用了Apache Portable Runtime(APR)作为最底层,使用了APR中包含Socket、缓冲池等多种技术,性能也提高了。APR也是Apache HTTPD的最底层。可想而知,同属于ASF(Apache Software Foundation)中的成员,互补互用的情况还是很多的,虽然使用了不同的开发语言。

     Tomcat 的线程池位于tomcat-util.jar文件中,包含了两种线程池方案。方案一:使用APR的Pool技术,使用了JNI;方案二:使用Java实现的ThreadPool。这里介绍的是第二种。如果想了解APR的Pool技术,可以查看APR的源代码。

     ThreadPool默认创建了5个线程,保存在一个200维的线程数组中,创建时就启动了这些线程,当然在没有请求时,它们都处理“等待”状态(其实就是一个while循环,不停的等待notify)。如果有请求时,空闲线程会被唤醒执行用户的请求。

     具体的请求过程是:服务启动时,创建一个一维线程数组(maxThread=200个),并创建空闲线程(minSpareThreads=5个)随时等待用户请求。当有用户请求时,调用 threadpool.runIt(ThreadPoolRunnable)方法,将一个需要执行的实例传给ThreadPool中。其中用户需要执行的实例必须实现ThreadPoolRunnable接口。 ThreadPool首先查找空闲的线程,如果有则用它运行要执行ThreadPoolRunnable;如果没有空闲线程并且没有超过 maxThreads,就一次性创建minSpareThreads个空闲线程;如果已经超过了maxThreads了,就等待空闲线程了。总之,要找到空闲的线程,以便用它执行实例。找到后,将该线程从线程数组中移走。接着唤醒已经找到的空闲线程,用它运行执行实例(ThreadPoolRunnable)。运行完ThreadPoolRunnable后,就将该线程重新放到线程数组中,作为空闲线程供后续使用。

     由此可以看出,Tomcat的线程池实现是比较简单的,ThreadPool.java也只有840行代码。用一个一维数组保存空闲的线程,每次以一个较小步伐(5个)创建空闲线程并放到线程池中。使用时从数组中移走空闲的线程,用完后,再“归还”给线程池。

posted @ 2010-12-16 14:46 洛可可 阅读(411) 评论(0) 编辑

   SOAP消息可以是XML文件,该文件中一定要包含SOAP Envelope(封装)和SOAPBody(体),而SOAP Header(头)则是可以选择性的。
   SOAP消息包含下列各项:
  ·Envelope是XML文件的顶层元素,代表该文件为SOAP消息。
  ·Header提供了向SOAP消息中添加关于这条SOAP消息的某些要素(feature)的机制,不需要事先与商业伙伴建立合约。SOAP定义了一些属性用于在Header中指定“谁”处理该功能,以及它是选择性的还是强制性的。
  ·Body就是接收者所要接收消息的容器。SOAP定义了一个元素供BoO使用,即Fault元素,用以报告错误。

    (1)SOAP Envelope
    SOAP Envelope消息必须有Envelope元素和名称空间lattp://schemas.xmlsoap.org/soap/envelope/来使 用,如果一个SOAP应用程序接收了一个消息,而该消息的SOAP Envelope元素使用和上述不同的名称空间,则该应用程序就将其视为版本错误并忽略该消息。如果消息使用。H\'I’TP的请求/响应通讯协议,应用 程序就必须响应一个SOAP的VersionMismatch错误码消息(使用 “http://schemas.xmlsoap.org/soap/envelope/”名称空间)。
    (2)SOAP Header
    为相互通信的团体之间提供了一种很灵活的机制,在无需预先协定的情况下,以分散但标准的方式扩展消息。可以在SOAP.Header中添加条目实现这种扩 展,如认证、事务管理、支付等。Header元素是SOAP封装元素的第一个直接子元素。Header元素的所有直接子元素称作条目。条目的编码规则如 下:
    .  一个条目有它的完整的元素名(包括名域URi和局部名)。SOAP Header的直接子元素必须有名称限制。
    .  SOAP encodingStyle属性可以用来指示条目所用的编码形式。
    .  SOAP mustLJnderstand属性和SOAPactor属性可以用来指示如何处理这个条目以及由谁来处理。
    (3)SOAP Body
    SOAP:Body提供一个简单的用于与消息的最终接收者交换信息的机制,这些信息都是必须处理的机制。Body元素的典型应用是包含序列的RPC调用和 错误报告。Body元素在代码中是SOAP Envelope元素的一个直接子元素。如果包含:Header元素,则Body元素必须直接跟随Header元素之后,是Header元素的直接下一个 兄弟元素,否则Body元素必须是Envelope元素的第一直接子元素。所有Body元素的直接子元素被称为Body条目,同时每一个:Body条目都 是SOAP Body元素中的一个独立元素。
    SOAP只预定义了一个Body条目:Fault用于向调用方报告错误。SOAP Fault元素是用于在SOAP消息中传输错误及状态信息。如果SOAP消息需要包含SOAP Fault元素,则SOAP Fault元素必须作为一个:Body条目出现,并在Body元素内只能出现一次。
    SOAP Fault元素定义了如下子元素:
    .faultcode。faultcode元素是满足了那些以算法机制来标识错误的软件的需要。faultcode元素必须在SOAP Fault元素中出现,同时它的值必须是属于其后定义的一个修饰名。SOAP定义了一个很小的SOAP错误代码的集合,用于覆盖基本的SOAP错 误。
    .faultstring。faultstring元素提供了错误代码的解释,它不是为程序处理而设。faultstring元素有点类似于HTTP中定义 的“Reason.Phrase”。faultstring元素必须在SOAP Fault元素中出现,同时提供一些解释错误种类的信息。
    .faultactor。faultactor的值是一个URi,它指出在消息路径上是哪个节点导致错误发生的信息。它类似于SOAP actor属性,不过它不是用于指示Header条目的接收者,而是用于指示错误源。faultactor元素的值是一个标识该源的一个uRI。作为 SOAP    消息的非最终接收者的应用程序必须在SOAP Fault元素中包含faultactor元素,而消息的最终接收者可以使用faultactor元素来明确地指明是它生成了该错误。
    ·detail。detail元素是用于传输与Body元素相关的应用程序特别的错误信息。如果Body元素中的内容不能被成功地处理时,detail元 素必须出现。detail元素不能被用于传输属于。Header条目的错误信息。详细的属于Header条目的错误信息必须在Header条目中传输。
    若Fault元素中不出现detail元素则表明其中的错误与Body元素的处理无关。这可以用于区分在错误情况下Body元素是否被处理过。 detail元素的所有直接子元素都被称为detail条目,同时每个detail条目都作为detail元素中的一个独立的元素进行编码。
    (4)SOAP消息的传送
    SOAP消息从发送方到接收方是单向传送,并且经常以请求/应答的方式实现。例如,HTTP绑定使SOAP应答消息以HTTP应答的方式传输,并使用同一个连接返回请求。不管SOAP被绑定到哪个协议,SOAP消息在终节点之外的中间节点也可以处理。
    一个接收SOAP消息的SOAP应用程序按照以下步骤来处理消息:
    .  识别应用程序需要的SOAP消息的所有部分;
    ·  检验应用程序是否支持第一步中识别的消息中所有必须需要的部分并处理它。如果不支持,则丢弃消息。在不影响处理结果的情况下,处理器可能忽略第一步中识别出的可选部分。如果这个SOAP应用程序不是这个消息的最终目的地,则在转发消息之前删除第一步中识别出来的所有部分。
    为了正确处理一条消息或者消息的一部分,SOAP处理器需要理解所用的交换方式(单向、请求/应答、多路发送等)、以及这种方式下接收者的任务、RPC机 制(如果有的话)的使用、数据的表现方法或编码,还有其他必须的语义。尽管属性(如SOAP Encoding Style)可以用于描述一个消息的某些方面,但这个规范并不强制所有的接收方也必须有同样的属性并取同样的属性值。即交互双方的SOAP消息并不一定要 遵循同样的格式设定,而只需要以一种双方可理解的格式交换信息就可以了。
    SOAP消息都使用XML形式编码。一个SOAP应用程序产生的消息中,所有由SOAP定义的元素和属性中必须包括正确的名称。SOAP应用程序必须能 够处理它接收到的消息中的SOAP名称,并且也可以处理没有SOAP名称的SOAP消息,就像它们有正确的名称一样。

 



posted @ 2010-12-15 15:06 洛可可 阅读(295) 评论(0) 编辑

消息形式:
点对点为两个客户之间建立消息队列,使两个客户端之间通过队列实现点对点的消息传递
注:类似数据结构里的队列,先进先出
主题消息,在消息中间件上建立一个主题,没个客户端都可已向这个主题发送消息,接受消息

注:类似广播的方式

开发流程:

 


使用JMS步骤

1.创建一个JNDI上下文

Context  init initCtx =new InitialContext(env);

2.查找创建JMS连接使用的工厂类(Connnect Factory)

对于主题消息:

Object tmp=initCtx.lookup(“Connnect Factory”);

TopicConnectionFactory tcf=( TopicConnectionFactory) tmp;

对于点对点消息:

Object tmp=initCtx.lookup(“Connnect Factory”);

QueueConnectionFactory tcf=( QueueConnectionFactory) tmp;

3.查找JMS的目标对象(Destination)

对于主题消息:

Topic topic=(Topic)iniCtx.lookup(“topic/testTopic”);

对于点对点消息:

Queue queue (Queue)iniCtx.lookup(“queue /A”);

4.创建JMS连接(Connection)

对于主题消息:

TopicConnection conn=tcp.createTopicConnection();

对于点对点消息:

QueueConnection conn=tcp.createQueueConnection ();

5.创建JMS会话(session)

对于主题消息:

TopicSession session=conn.createTopicSession(fasle,Session.AUTO_ACKNOWLEDGE);

对于点对点消息:

QueueSession session= conn.createQueueSession(true,0);

6.创建消息的生产和消费者

生产者:

对于主题消息:

TopicPublisher publisher=session.createPublisher(topic);

对于点对点消息:

QueueSender sender = session.createSender (queue);

消费者:

对于主题消息:

TopicSubscriber subscriber=session.createSubscriber (topic);

对于点对点消息:

QueueReceiver receiver= session.createReceiver (queue);

7.注册消息的监听者

对于主题消息:

TextListener listener=new TextListener();

subscriber.setMessageListener(listener);

对于点对点消息:

TextListener listener=new TextListener();

receiver.setMessageListener(listener);

8.开始JMS的连接

   conn.start();

9.发送和接受消息

发送消息:

对于主题消息:

publisher.publish(message);

对于点对点消息:

sender.send(message);

接受消息:

对于主题消息:

Message msg= subscriber.receive();

对于点对点消息:

Message msg= receiver.receive(1000);

10.停止和关闭JMS连接

conn.stop();

session.close();

conn.close();

转自:http://www.mldn.cn/articleview/2007-2-6/article_view_1377.htm

posted @ 2010-07-30 14:42 洛可可 阅读(101) 评论(0) 编辑

   Java消息发送服务(Java Messaging Service,JMS)是提供商无关的一套API,用于在程序间进行可靠的消息发送。在客户端-服务器计算中,客户端程序与服务器与服务器建立联系并请求服务。相反,消息发送应用在相互协作的程序之间发送消息。有些程序(在所谓的“对等(peer-to-peer)”应用中)则相互之间直接交换信息(JXTA使用的就是这种模型)。

JMS提供了一个中间件消息代理(message broker),后者提供了程序间可靠的、事务性的消息发送。

    虽然这些图中显示的消息提供者和消费者都是物理上的机器,实际上它们也可以是运行在一台或者多台机器上的相互协作的一些进程。

    JMS提供者是一个程序,它实现了JMS公共接口中的JMS服务约定。J2EE平台规范要求平台实现包含一个JMS提供者。

    大多数人都比较熟悉客户端-服务器模型的消息发送,在这种模型中,客户端程序与服务器建立联系,请求服务、数据,或者同时请求服务和数据。相反,JMS提供了一种更丰富的消息发送模型,这种模型具有以下高级特性:

    可靠的消息发送。当消息发送者正在发送消息时,消息接受者无需处于运行状态。而是等等接受者下次做好准备时,再将消息发送到接受者手上。
   点到点或者发布/订阅式的消息发送模型。消息的传送可能是一对一的,也可能是一对多的。
    事务。消息发送可作为一个分布式事务的一部分。
   同步的或异步的消息发送。消息生产者可能会等待接受者的确认,也可能不会。
   面向对象的消息发送。JMS允许在客户端之间发送对象,而不是通过使用一些协议来发送结构化的数据。
   遗留整合。JMS可以与底层的第三方消息发送系统进行整合。
  本期解释了如何使用JMS消息队列来实现两个进程之间简单、可靠的点到点的消息发送。发布/订阅式的消息发送将在后面的期“Enterprise Java Technologies Tech Tips”中讲述。

 

JMS队列术语

JMS使用消息队列的概念来实现点到点的消息发送。在点到点的消息发送中,总是有一个明确的消息生产者和一个消息消费者。在点到点的消息发送中,与时间没有多大的关系,除非消息发送者为消息定义了一个期限。消息接受这可以接收由消息生产者在过去任何一个时候发送的消息,即使在该消息被编入队列时消息消费者没有处于运行状态。

JMS提供者是一个消息发送服务器,它负责处理消息的持久性、超时、重发、事务回滚以及由JMS提供的其他服务。对于J2EE SDK这种情况,JMS提供者是J2EE服务器程序的一部分。消息生产者发送对象到由JMS维护的一个队列中。消息消费者则从该队列接收消息,并发出确认,表示已经收到消息。

JMS规范定义了一些可用于在进程间发送消息的对象:

JMS管理的对象。有两种JMS管理的对象:目的地和连接工厂。这两种对象都是由系统管理员通过环境管理工具创建的。
目的地。这是一种服务器端的对象,通过这个对象进行消息的发送和接收。JMS队列就是一种目的地对象。
连接工厂。这是一种服务器端的对象,负责配置和创建到一个特定目的地的连接。JMS 队列的JMS连接工厂就是一种QueueConnectionFactory。
连接。这是一种到一个JMS提供者(而不是到一个目的地)的虚拟连接。它被用来创建会话。用于访问队列的一个连接就是一种QueueConnection。
会话。这是一个潜在的消息传送和接收的事务性的工作单元。会话用于创建消息、消息生产者和消息消费者。用于访问队列的一个会话就是一种QueueSession。
消息。这是一种可以从消息目的地发送到消息消费者的对象。消息的类型随要发送的对象类型的不同而不同。例如,为本期提供的示例代码就使用了TextMessage对象。
消息生产者。这是一种由JMS客户端程序使用的、用于发送消息到目的地的对象。JMS客户端程序从一个会话中获取消息生产者对象。程序可以使用QueueSender这种类型的消息生产者对象来发送消息到一个队列中。

消息消费者。这是一种由JMS客户端程序使用的、用于从一个目的地接收消息的对象。JMS客户端程序从一个会话中获取消息接受者对象。程序可以使用QueueReceiver这种类型的消息消费者对象来从一个队列中接收消息。
这里颇有几个新的术语。现在让我们看看如何发送消息。以下步骤展示了从与本期一起提供的示例代码中抽出的一些例子。(想知道如何下载和运行该示例代码,请参考运行示例代码一节。)不过,在运行示例代码之前,你需要配置一下服务器(参见 配置服务器一节)。

 


发送消息

J2EE参考实现预先配有一个队列连接工厂(名为QueueConnectionFactory)和一个队列(名为jms/Queue)。如果你使用的是JMS服务器,而不是参考实现,或者如果你想试着更改队列连接工厂和/或队列队列的名称,请参考配置服务器一节。

下面是通过一个JMS队列发送消息的步骤。从示例程序TestQueue中抽出的代码片段也穿插在这些步骤中。

通过按名字在JNDI中进行查找,获得一个指向QueueConnectionFactory 的引用:

    protected static String qfactoryName =3.
            "jms/queue/TechTipsQueueConnectionFactory";4.
         ...
         try {
         // 获得JNDI上下文
         InitialContext ctx = new InitialContext();
         // 获得连接工厂
         QueueConnectionFactory qcf =
         (QueueConnectionFactory)ctx.lookup(qfactoryName);


2.从 QueueConnectionFactory获得一个QueueConnection,再从这个连接获得一个QueueSession 。按名字在JNDI中查找:


      // 获得一个到队列的连接
       qc = qcf.createQueueConnection();
       //从该连接获得一个会话
       QueueSession qs = qc.createQueueSession(
           false, Session.AUTO_ACKNOWLEDGE);
      // 获得一个队列
      Queue q = (Queue)ctx.lookup(queueName);

3. 使用QueueSession创建一个QueueSender,将该队列作为一个参数来传递。(QueueSender是QueueSession与某个特定队列之间的一个关联。):


      // 使用这个会话创建一个QueueSender 
      // and a TextMessage.
      QueueSender qsnd = qs.createSender(q);


现在可以用QueueSender来发送消息到队列。

4. 创建一个消息对象(Message的子类),然后使用QueueSender的发送方法将它们发送至目的地。示例程序从Session中获得一个TextMessage对象。接着示例程序将每个程序参数打包到TextMessage 中,然后使用QueueSender将其发送至队列。注意,同一个TextMessage 可以使用多次。


      TextMessage tm = qs.createTextMessage();
       
      // 为第一个参数之后的每个参数进行一次循环
      // 以文本消息的形式发送参数字符串
      for (int i = 2; i < args.length; i++) {
          tm.setText(args[i]);
          qsnd.send;
      }

5.关闭QueueConnection。在try/finally程序块的最后一条语句中关闭连接是一个好习惯。这一步很重要:忘记关闭 QueueConnections 将可能导致服务器上的资源泄漏:


  } finally {
          if (qc != null) {
              qc.close();

          }
      }


要发送消息到一个消息队列,可以使用TestQueue程序(在缺省的包中),加上一个参数“send”,例如:

$ java TestQueue send jms/queue/MyTestQueue a b c d
Java Message Service 1.0.2 Reference
Implementation (build b14)
Sent: 'a'
Sent: 'b'
Sent: 'c'
Sent: 'd'


接收消息

TestQueue程序按照以下步骤接收消息:

和2从一个消息队列接收消息的起先两步与发送消息是一样的:先是查找连接工厂,再获得一个QueueConnection,然后查找Queue。
从QueueSession 获得一个QueueReceiver :
QueueReceiver qrcv = qs.createReceiver(q);
3.    从Queue接收消息。示例程序进入一个循环,在这个循环中从队列获取消息并将它们打印到标准输出设备。


         qc.start();
         Message m = qrcv.receive(10000);
         while (m != null) {

             if (m instanceof TextMessage) {
                 TextMessage tm = (TextMessage)m;
              System.out.println("Received text: '" +
                                 tm.getText() + "'");
          } else {
              System.out.println("Received a " +
                              m.getClass().getName());
          }
          m = qrcv.receive(100);
      } finally {
         if (qc != null) {
             qc.close();
          }
      }

对QueueConnection的启动方法的调用将告诉连接开始接收消息。QueueReceiver接收方法带有一个参数,该参数表明了等待一条消息的毫秒数。如果消息没有在规定时间内到达,该方法将返回null值。直到消息队列在100毫秒的时间内都保持为空,程序才开始读取和打印收到的消息。在try/finally程序块的结尾有一个finally子句,该子句像前面例子中一样地关闭QueueConnection。

要接收消息队列中的消息,可以使用TestQueue程序,再带上一个参数“recy”,例如:

$ java TestQueue recv jms/queue/MyTestQueue
Java Message Service 1.0.2 Reference
Implementation (build b14)
Received text: 'a'
Received text: 'b'
Received text: 'c'
Received text: 'd'


配置服务器

如果你使用的不是参考引用,或者你想更改队列和/或队列连接工厂的名字,你就需要通过使用平台的管理工具配置JMS提供者。队列或者连接工厂被创建之后,便留在服务器中,直到服务器重新启动。有些平台实现可能会为客户端提供扩展API,以便程序化地创建目的地和连接工厂。

用来在J2EE SDK下创建受管理的对象的工具是。要配置服务器,需:

启动应用服务器。
Create a message queue, giving it a JNDI name. (Do this only once.) To create a
new message queue in the J2EE SDK, first decide on a name for your message
queue. It can be convenient for administration purposes to choose a name that
indicates that the queue is used by JMS, for example, jms/MyTestQueue. Then
execute the command:创建一个消息队列,并为它取一个JNDI名。(只做一次。)要用J2EE SDK创建一个新的消息队列,首先需要为消息队列决定一个名字。为了便于管理, 应该选择一个可以表明该队列是JMS使用的队列,例如jms/MyTestQueue。然后执行命令:
             j2eeadmin -addJmsDestination <queuename> queue

用消息队列的实际名字替换<queuename> 。

由于连接工厂名QueueConnectionFactory被硬性地放在示例程序中,因此要告诉程序使用一个不同的连接工厂名,就必须修改源代码,并且重新编译。例如,在TestQueue.java中:

        // Change this variable's value to change the 
       // connection factory name
       protected static String qfactoryName =
                          "QueueConnectionFactory"


重新编译之后,使用j2eeadmin(或者你自己的服务器的工具)创建一个connection factory,给它取个JNDI名,如:

j2eeadmin -addJmsFactory jms/MyQueueConnectionFactory

要列出连接工厂,使用:

j2eeadmin -listJmsFactory

要列出目的地,使用:

j2eeadmin -listJmsDestination

对于不是J2EE SDK的平台,可以在该平台上使用J2EE产品的部署工具来创建所需的消息队列和连接工厂。


运行示例代码

下载这些期的示例存档。这个JAR文件包含了示例程序的完整源代码,包括Java程序文件和HTML格式的文件。你可以使用命令jar xvf ttmar2003.jar 将示例jar中的内容解压缩到你的工作目录下。在运行示例程序前,要确保J2EE服务器正在运行。

多次运行示例程序。试着发送一些成批的消息,但是不接收这些消息,检查一下输出的顺序。

这个示例程序为你试着使用JMS队列提供了切入点。探索一下JMS接口使用的API。例如,可以更改一下程序,试着使用三种不同的接收方式。探索一下事务性的消息发送,或者试着发送各种类型的消息对象。JMS有许多特性,熟练使用它可以提高你的应用设计水平。

   转自:http://www.mldn.cn/articleview/2007-1-23/article_view_994.htm

posted @ 2010-07-30 14:37 洛可可 阅读(79) 评论(0) 编辑

    当我在一日复一日的虚度和自责中挣扎时,突然发现我不应该后悔,人生是很短的旅程,今天过去了,将永远也不会回来了,而我今天过得如何,也将无法重复。

    明天也许会美好,也许会艰难,那都是一个过程而已,不要牺牲今天的快乐去赌未知的明天。

   我只需要问问我的心,延续曾经的梦想,不要放弃,能开心则开心。

   人生不是只有一条路,也不应该把一切都放在一个篮子里,使自己足够的坚强和强大,才会充满希望。

   OK,把握时间,既要好好的完成学业,又要在其他方面有所收获,不要借口和犹豫!

   忘记后悔和抱怨吧,如果真的觉得在虚度光阴,那就立刻补救吧,一切还来及!

posted @ 2010-07-29 21:05 洛可可 阅读(15) 评论(0) 编辑
摘要: 来源:互联网 酷勤网整理 让我们来看看上述代码的详细内容。JDBCSAXParser包括了几个重载的parse()方法。在下表中org.xml.sax.Parser接口需要实现parse(InputSource)与parse(String)方法。其它parse()方法简化了代码并允许通过派生类重载以改变其解析方法。 如果参数为JDBCInputSource类型,Parse(InputSource...阅读全文
posted @ 2010-07-27 09:45 洛可可 阅读(57) 评论(0) 编辑
摘要: 来源:互联网 酷勤网整理 数据库和XML提供了数据存储的完整功能。数据库保存数据用于高效的数据查询,而XML则提供了一种不同应用间信息交换的简单途径。为了利用XML的优点,我们需要将数据库表转化为XML文档。然后我们便可以使用指定的XML工具对这些文档进行其它处理。例如,XML文档可通过XSLT样式表转化为HTML页显示,或通过如XQL这样基于XML的查询语言进行检索,或作为一种数据交换格式,等...阅读全文
posted @ 2010-07-27 09:25 洛可可 阅读(22) 评论(0) 编辑