使用CXF和camel-cxf调用webservice

2023-05-16

CXF是什么

Apache CXF 是一个开源的、全功能的WebService框架,它提供了一套工具和API来帮助开发和构建WebService,像 JAX-WS 和 JAX-RS。它也支持许多WebService标准,例如:

    • SOAP
    • WS-Addressing
    • WS-Policy
    • WS-ReliableMessaging
    • WS-SecureConversation
    • WS-Security
    • WS-SecurityPolicy

和许多其他的特性。[更多的请参考 http://en.wikipedia.org/wiki/Apache_CXF]

demo.wsdl 是本文中使用的示例wsdl文件.

使用CXF调用WebService

每个WebService服务都需要提供一套用于外部调用的接口,也需要提供对应于这些接口调用的输入输出数据格式。用于规范这些接口和消息格式定义的标准就是 WSDL 。在本节里,将讨论如何使用CXF 来开发一个基于某个WSDL的WebService客户端。 (这里假设使用的传输协议为 HTTP,更多的可以参考本博客里的关于CXF的介绍的文章).

本质上,每个基于 HTTP 的WebService服务都等价于一个接收 HTTP-POST 请求的HTTP服务,为了调用这个服务,用户只需要知道如何构造一个期望的HTTP POST请求格式,例如:

 


POST http://localhost:8040/services/WebService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "http://www.talend.org/service/WebServiceOperation1"
Content-Length: 307
Host: localhost:8040
Connection: Keep-Alive
 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://www.talend.org/service/">
   <soapenv:Header/>
   <soapenv:Body>
      <ser:WebServiceOperationRequest1>
         <in>Hello</in>
      </ser:WebServiceOperationRequest1>
   </soapenv:Body>
</soapenv:Envelope>  
 可以使用Java  HTTP API 发送以上请求:

 

 


//request content
String content = "<soapenv:Envelope"
        + " xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\""
        + " xmlns:ser=\"http://www.talend.org/service/\">"
        + "<soapenv:Body><ser:WebServiceOperationRequest1><in>Hello</in>"
        + "</ser:WebServiceOperationRequest1></soapenv:Body>"
        + "</soapenv:Envelope>";
 
//service url
URL url = new URL("http://localhost:8040/services/WebService");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
 
//set soapaction
connection.addRequestProperty("SOAPAction",
        "http://www.talend.org/service/WebServiceOperation1");
connection.setDoOutput(true);
connection.setDoInput(true);
 
//send out request
OutputStream os = connection.getOutputStream();
os.write(content.getBytes());
os.flush();
 
//read response and print out
InputStream is = connection.getInputStream();
int available = is.available();
byte[] response = new byte[available];
is.read(response);
System.out.println(new String(response));
 
os.close();
is.close();  

 

从以上代码里可以看出,为了使得调用成功,我们需要关心从请求信息到连接信息的几乎每个细节。因此这里,我们将介绍如果使用CXF 来简化请求,从而让用户可以只关注业务逻辑部分,再底层细节由CXF 处理。

CXF 提供了好几种调用WebService的方法,详细的可以参考本博客里的相关文章。这里就介绍两种:Provider-Dispatch 和 JAX-WS

 Provider-Dispatch

Provider-Dispatch 是一种类似于 Java HTTP 的方式,好处就是灵活、方便、强大,缺点就是和Java HTTP 一样,用户需要知道如何构建一个合格的消息。更多的可以看 http://liugang594.iteye.com/blog/1964510  。

JAX-WS

JAX-WS 是 Java API for XML Web Services 的简称,它是用于创建WebService的Java API,它定义了一个用于Java-WSDL映射的标准,例如WSDL接口如何绑定到Java方法,以及SOAP消息如何匹配到方法的参数等。

为了简化 WSDL 和 Java的映射, CXF 提供了一些工具和API用于Java和WSDL之间的转换,这里只展示如何从WSDL转成Java.

WSDL2Java 命令行

CXF 提供了一个 wsdl2java 命令行工具用于从 WSDL 转换到 Java,有很多可用的选项,以下列出了主要的几个选项:[更多的可以访问 https://cxf.apache.org/docs/wsdl-to-java.html ]:

Option

Interpretation

-p [ wsdl-namespace= ] PackageName

Specifies zero, or more, package names to use for the generated code. Optionally specifies the WSDL namespace to package name mapping.

-d output-directory

Specifies the directory into which the generated code files are written.

wsdlurl

The path and name of the WSDL file to use in generating the code.

例如要生成对应于以上 demo.wsdl的代码,可以使用以下命令:

 

wsdl2java -p org.talend.esb.camel.cxf -d output  demo.wsdl
 

 

完成以后就可以看到生成的代码列表:

更进一步的,后 6 类分别对应于WSDL中的 Service(s), DataTypes 和 PortType(s)从Java对象到 WSDL 和 XML 元素的映射关系由annotation决定。这里,生成的代码里有两类annotation:

JAX-WS annotations

这类annotation主要用于Java和WSDL之间的映射These annotations are mainly used to map a java class to Web Service.

AnnotationDescription
WebServiceEvery Class who wants to be published as a Web Service should be annotated by this annotation
SOAPBindingDefine the SOAP Binding style of this service
WebResultDefine the mapping from method return object to WSDL operation output
WebMethodDefine the mapping between Java method to WSDL operation
WebParamDefine the mapping between method argument to WSDL operation Input

访问 https://jax-ws.java.net/jax-ws-ea3/docs/annotations.html 以了解每个annotation的更多细节。

JAXB Annotations

JAX-WS annotations用于java到 WSDL之间的映射,而JAXB annotation则是用于Java对象到XML结构的映射。 JAXB 是 CXF 默认的数据映射方式,用户也可以使用以下参数指定其他的映射方式:

-db

下面是生成代码里用到的 JAXB 相关的annotation说明:

AnnotationDescription
XmlAccessorTypeUsed on a class to specify which members will be mapped to xml, for example FIELDPUBLIC
XmlElementUse to indicate the member will be mapped to an xml element
XmlTypeUsed on a class to specify the generated xml type of this class
XmlRootElementUsed to indicate it can be a root element of xml

有了这些类后,可以很容易的用他们来调用WebService了:


//create service instance
Service service = Service.create(new URL("http://localhost:8040/services/WebService?wsdl"), new QName("http://www.talend.org/service/", "WebService"));
//create port from service
WebServicePortType port = service.getPort(WebServicePortType.class);
//input parameter
WebServiceOperationRequest1 operationRequest1 = new WebServiceOperationRequest1();
operationRequest1.setIn("World");
//invoke, and get response
WebServiceOperationResponse1 operationResponse1 = port.webServiceOperation1(operationRequest1);
//print out the result
System.out.println(operationResponse1.getOut());  

只需要知道wsdl的路径和service的qname,其他的都是普通的Java对象。

注意:返回值也是一个对象,而不是普通的XML内容,可以使用以下代码进行转换:

Object to XML
1
2
3
JAXBContext context = JAXBContext.newInstance(WebServiceOperationResponse1. class );
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(operationResponse1, System.out);

 

WSDL2Java API 

除了命令行,也可使用代码来进行wsdl到java的转换:


WSDLToJava wsdlToJava = new WSDLToJava(new String[]{"-p", "org.talend.esb.camel.cxf", "-d", "output",  "demo.wsdl"});
wsdlToJava.run(new ToolContext());  

使用camel-cxf调用WebService

camel-cxf 组件是基于 CXF的,它提供了在Camel中访问WebService的能力。 

URI 格式

 

cxf:bean:cxfEndpoint[?options]
当  cxfEndpoint 代表一个已经注册了的Bean的ID。使用这种格式的URI,节点的大部分内容在Bean里定义。

 

或者:

 

cxf://someAddress[?options]
 这里  someAddress 指定了  CXF 端点的地址。使用这种格式的URI,节点的大部分定义是由选项指定的。本文里只讨论这种格式。

 

选项

camel-cxf组件提供了很多可用的选项,对于consumer端,大部分有用的选项都在下表中:[ 更多的请看 http://camel.apache.org/cxf.html ]:

 

Name

Required

Description

wsdlURL

No

The location of the WSDL. It is obtained from endpoint address by default. 

Example: file://local/wsdl/hello.wsdl or wsdl/hello.wsdl

serviceClass

Yes

The name of the SEI (Service Endpoint Interface) class. This class can have, but does not require, JSR181 annotations. 
This option is only required by POJO mode. If the wsdlURL option is provided, serviceClass is not required for PAYLOAD and MESSAGE mode. When wsdlURL option is used without serviceClass, the serviceName and portName (endpointName for Spring configuration) options MUST be provided. It is possible to use # notation to reference a serviceClass object instance from the registry. E.g. serviceClass=#beanName. The serviceClass for a CXF producer (that is, the to endpoint) should be a Java interface.
Since 2.8, it is possible to omit both wsdlURL and serviceClass options for PAYLOAD and MESSAGE mode. When they are omitted, arbitrary XML elements can be put in CxfPayload's body in PAYLOAD mode to facilitate CXF Dispatch Mode. 

Please be advised that the referenced object cannot be a Proxy (Spring AOP Proxy is OK) as it relies onObject.getClass().getName() method for non Spring AOP Proxy. 

Exampleorg.apache.camel.Hello

serviceName

No

The service name this service is implementing, it maps to the wsdl:service@name

Required for camel-cxf consumer since camel-2.2.0 or if more than one serviceName is present in WSDL. 

Example: {http:­//org.apache.camel}ServiceName

portName

No

The port name this service is implementing, it maps to the wsdl:port@name

Required for camel-cxf consumer since camel-2.2.0 or if more than one portName is present under serviceName

Example: {http:­//org.apache.camel}PortName

dataFormat

No

The data type messages supported by the CXF endpoint. 

DefaultPOJO 
ExamplePOJOPAYLOADRAW

DataFormat的描述如下:

DataFormat

Description

POJO

POJOs (Plain old Java objects) are the Java parameters to the method being invoked on the target server. Both Protocol and Logical JAX-WS handlers are supported.

PAYLOAD

PAYLOAD is the message payload (the contents of the soap:body) after message configuration in the CXF endpoint is applied. Only Protocol JAX-WS handler is supported. Logical JAX-WS handler is not supported.

RAW

RAW is the raw message that is received from the transport layer. It is not suppose to touch or change Stream, some of the CXF interceptor will be removed if you are using this kind of DataFormat so you can't see any soap headers after the camel-cxf consumer and JAX-WS handler is not supported.

CXF_MESSAGE

New in Camel 2.8.2CXF_MESSAGE allows for invoking the full capabilities of CXF interceptors by converting the message from the transport layer into a raw SOAP message

DataFormats

RAW

camel-cxf支持4种DataFormat,下面将显示每种DataFormat的特点与不同:

 


from("timer:foo?repeatCount=1")       
        .setBody(constant(content))             //set request body
        .to("cxf:"
                + "http://localhost:8040/services/WebService" //service address
                + "?"
                + "wsdlURL=http://localhost:8040/services/WebService?wsdl"    //wsdl url
                + "&"
                + "dataFormat=RAW"        //dataformat type
            )
        .convertBodyTo(String.class)
        .to("log:output");  

以上代码示例的作用和最上的Java HTTP API效果是一样的,这里用的 dataFormat 为 RAW,请求内容为:


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:ser="http://www.talend.org/service/">
    <soapenv:Body>
        <ser:WebServiceOperationRequest1>
            <in>Hello</in>
        </ser:WebServiceOperationRequest1>
    </soapenv:Body>
</soapenv:Envelope>  

 

对于RAW,可以看出,整个soap envelope的结构都需要指定,返回值也是一个完整的Envelope的结构:

 


<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <tns:WebServiceOperationResponse1 xmlns:tns="http://www.talend.org/service/">
            <out>Hello</out>
        </tns:WebServiceOperationResponse1>
    </soap:Body>
</soap:Envelope>  

PAYLOAD

不同的DataFormat,请求内容的格式也是不一样,例如上例中,把RAW 换成 PAYLOAD,则内容需要指定为:


<ser:WebServiceOperationRequest1 xmlns:ser="http://www.talend.org/service/">
    <in>Hello</in>
</ser:WebServiceOperationRequest1>  

只有soap body节点内的内容需要指定,返回的结果也是只有soap body内的内容:

 


<tns:WebServiceOperationResponse1 xmlns:tns="http://www.talend.org/service/">
    <out>Hello</out>
</tns:WebServiceOperationResponse1>  

 

CXF_MESSAGE

CXF_MESSAGE 类似于 RAW,它也要求整个soap envelope的结构,但是内容对象需要是一个 javax.xml.transform.Source 实例,因此需要先把内容转成一个 javax.xml.transform.Source 对象:

 


from("timer:foo?repeatCount=1")       
        .setBody(constant(content))             //set request body
        .convertBodyTo(DOMSource.class)         //convert content to a DOMSource instance
        .to("cxf:"
                + "http://localhost:8040/services/WebService" //service address
                + "?"
                + "wsdlURL=http://localhost:8040/services/WebService?wsdl"    //wsdl url
                + "&"
                + "dataFormat=CXF_MESSAGE"        //dataformat type
            )
        .convertBodyTo(String.class)
        .to("log:output");  
可以看到除了把  RAW 变成  CXF_MESSAGE,还添加了 " .convertBodyTo(DOMSource.class)" 用于转换 " setBody(constant(content))" 里的内容,否则会得到异常,返回的结果和  RAW一样:

 

 


<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/>
    <soap:Body>
        <tns:WebServiceOperationResponse1 xmlns:tns="http://www.talend.org/service/">
            <out>Hello</out>
        </tns:WebServiceOperationResponse1>
    </soap:Body>
</soap:Envelope>  

除了请求内容实例外,RAW 和 CXF_MESSAGE 主要区别在于:CXF_MESSAGE 拥有完全的 CXF interceptor功能,而他们中的一些则不能用在 RAW 类型上。

 POJO

POJO 意味着请求的对象内容是一个普通的java对象,而不是xml结构的内容。camel-cxf 在底下会把这个对象转换成一个xml结构的内容,这点像我们之上JAX-WS一节介绍的内容。例如重用以上生成的 WebServiceOperationRequest1 类去创建请求:


from("timer:foo?repeatCount=1")
        .process(new Processor() {      //use processor to set body
            public void process(Exchange arg0) throws Exception {
                WebServiceOperationRequest1 request1 = new WebServiceOperationRequest1();
                request1.setIn("Hello1");
                arg0.getIn().setBody(request1);
            }
        })
        .to("cxf:"
                + "http://localhost:8040/services/WebService" // service address
                + "?"
                + "wsdlURL=http://localhost:8040/services/WebService?wsdl" // wsdl url
                + "&"
                + "serviceClass=org.talend.esb.camel.cxf.WebServicePortType" //serviceClass
                + "&" + "dataFormat=POJO" // dataformat type
        ).to("log:output");  

和之前的代码比较,有一些变化:

  1. setBody() 换成一个 Processor
    根据我们的讨论,一个 POJO 对象需要设置成body,因些这里使用 Processor 去设置body 
  2. 选项 serviceClass 需要被指定
    当使用POJO时,需要指定 serviceClass 这个选项用来指定Service类。

输出对象不能被转成一个string,因此这里直接打印出来:

 

Exchange[ExchangePattern: InOnly, BodyType: org.apache.cxf.message.MessageContentsList, Body: [org.talend.esb.camel.cxf.WebServiceOperationResponse1@19aa5882]]

可以看出,返回的值是一个 org.talend.esb.camel.cxf.WebServiceOperationResponse1 实例。

Headers

有一些headers可以用来影响camel-cxf的行为,例如如果没有指定operation,那么在WSDL中定义的第一个会被使用到,例如在我们的示例 demo.wsdl 里有两个operation,总是会使用第一个。如果检测一下camel-cxf可用的选项,有两个和operation相关的:

Name

Required

Description

defaultOperationName

No

New in 2.4, this option will set the default operationName that will be used by the CxfProducer which invokes the remote service. 

Defaultnull 
ExampledefaultOperationName=greetMe

defaultOperationNamespace

No

New in 2.4. This option will set the default operationNamespace that will be used by the CxfProducer which invokes the remote service. 

Defaultnull 
ExampledefaultOperationNamespace=http://apache.org/hello_world_soap_http

可以指定缺省值,而不是总使用第一个。除了选项,有两个header可以用来指定operation,一旦指定,缺省值就会被覆盖:

Header Name

Description

operationName

Specify the operation name which you are calling

operationNamespace

Specify the operation namespace which you are calling

另外,默认 SOAPAction 的值是空的,可以通过指定header的方式指定它: setHeader("SOAPAction", constant("http://www.talend.org/service/WebServiceOperation2")) ,这个值会作为HTTP的头发送。实际上所有自定义的头都会作为HTTP的头发送,例如:

 

setHeader("CorrelationID", constant("ADLKLWE-SADFA-EWEFFSAD_SADFASLFKAF"))

 

在传输时会变成:CorrelationID: ADLKLWE-SADFA-EWEFFSAD_SADFASLFKAF

Interceptor & Feature

当使用 CXF两个重要的部分需要提到: Interceptor and Feature。以下是从CXF网站上拷过来的:

Feature: in CXF is a way of adding capabilities to a Server, Client or Bus. For example, you could add the ability to log messages for each of these objects, by configuring them with a LoggingFeature. To implement a Feature, you must subclass AbstractFeature. //cxf.apache.org/docs/features.html

 

Interceptor: the fundamental processing unit inside CXF. When a service is invoked, an InterceptorChain is created and invoked. Each interceptor gets a chance to do what they want with the message. This can include reading it, transforming it, processing headers, validating the message, etc.

 camel-cxf中,我们通过CxfEndpoint 来安装 features 和 Interceptors,例如安装loggingFeature:

//create Endpoint
Endpoint cxfEndpoint = endpoint("cxf:"
                + "http://localhost:8040/services/WebService" // service address
                + "?"
                + "wsdlURL=http://localhost:8040/services/WebService?wsdl" // wsdl url
                + "&" + "dataFormat=PAYLOAD" // dataformat type
            );
 
//add feature
((CxfEndpoint)cxfEndpoint).getFeatures().add(new LoggingFeature());
 
//create route
from("timer:foo?repeatCount=1").setBody(constant(content))    // set request body
        .to(cxfEndpoint);

LoggingFeature会记录在client端和server端传输的输入输出消息。我们也可以使用Interceptors来达到同样的功能,如果看LoggingFeature的源码就会发现,在底层,它使用了LoggingInInterceptor 和 LoggingOutInterceptor,这就意味着我们可以用他们替换 LoggingFeature:

//create Endpoint
Endpoint cxfEndpoint = endpoint("cxf:"
                + "http://localhost:8040/services/WebService" // service address
                + "?"
                + "wsdlURL=http://localhost:8040/services/WebService?wsdl" // wsdl url
                + "&" + "dataFormat=PAYLOAD" // dataformat type
            );
 
//add Interceptor
((CxfEndpoint)cxfEndpoint).getInInterceptors().add(new LoggingInInterceptor());
((CxfEndpoint)cxfEndpoint).getOutInterceptors().add(new LoggingOutInterceptor());
 
 
//create route
from("timer:foo?repeatCount=1").setBody(constant(content))    // set request body
        .to(cxfEndpoint);

结果和使用Feature是一样的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用CXF和camel-cxf调用webservice 的相关文章

随机推荐

  • Linux下如何启动Tomcat像Windows启动并显示控制台日志信息一样?

    Linux 下如何启动Tomcat 像Windows 启动并显示控制台日志信息一样 xff1f Windows 下启动tomcat xff0c 一般直接运行startup bat xff0c 启动后如下图所示 xff1a Linux 下直接
  • An overview of time series forecasting models

    An overview of time series forecasting models 2019 10 04 09 47 05 This blog is from https towardsdatascience com an over
  • swap与zRam能否提升游戏性能【转】

    http bbs angeeks com thread 2384563 1 1 html 先来谈谈swap xff0c swap是创建在sdcard上的一个缓存文件或者也可以创建在手机NAND上的 xff0c 其两者的速度不 说 xff0c
  • 如何在linux脚本里面套娃运行脚本

    直接在脚本里面写sudo bash xx sh 有时候可能会出现问题 xff0c 这个时候就可以使用gnome重新打开新终端运行 首先安装gnome的库 sudo apt get install gnome terminal 然后在脚本里面
  • 树莓派如何设置开机自启动脚本

    参考文章 xff1a 史鑫龙 xff1a 树莓派开机自动执行程序 通过桌面启动 by xinlong 通过该文章的操作可以实现开机启动python程序 xff0c 但并不能实现开机运行shell脚本 xff0c 结合我之前的文章发现配合gn
  • Markdown学习记录

    Markdown 1 代码块 xff1a 代码块语法 xff1a 96 96 96 python 96 96 96 shell 1 python代码 print 34 Hello World 34 2 shell脚本 linux下重启的命令
  • MAC终端代理设置

    移动开发有时需要设置代理 xff0c 不然太慢 在终端中输代码即可显示隐藏文件 defaults write com apple finder AppleShowAllFiles boolean true killall Finder 再次
  • C#:如何查看.net core版本?

    C xff1a 如何查看 net core版本 xff1f 打开控制面板 xff0c 选择 程序和功能 xff0c 找到下图选项 xff0c 即可查看 net core版本 检查是否已正确安装所有内容 xff1a 安装完成后 xff0c 打
  • Qt信号槽如何传递参数

    Qt信号槽如何传递参数 利用 Qt 进行程序开发时 xff0c 有时需要信号 槽来完成参数传递 带参数的信号 槽在使用时 xff0c 有几点需要注意的地方 xff0c 下面结合实例进行介绍 1 当信号与槽函数的参数数量相同时 xff0c 它
  • 解决 zsh: command not found 报错

    问题描述 最近在开发 Go 项目 xff0c 使用 go get u xxxx 成功下载安装包后 xff0c 在终端执行新下载包的命令 xff0c 一直报 zsh command not found 的错误 一开始以为是包没安装成功 xff
  • Ubuntu 安装scipy错误解决办法

    在ubuntu 14 04使用pip3 install scipy时报错 xff1a numpy distutils system info NotFoundError no lapack blas resources found 百度了一
  • LA5016-IIC EEPROM协议解析

    写入 LA5016 解析协议设置 xff1a 波形 读取 波形 xff1a
  • Linux下安装oracle数据库提示DISPLAY not set. Please set the DISPLAY and try again.解决方法

    问题描述 xff1a Linux下安装oracle数据库提示DISPLAY not set Please set the DISPLAY and try again 如下图所示 xff1a 解决办法 xff1a 切换到root 用户 xff
  • html 清除缓存样式

    autocomplete 61 off
  • ArcGIS Server for linux 服务无法启动解决简记

    今天在一台Linux虚拟机上安装了一个ArcGIS Server For Linux 只ArcSOC 组件 xff0c 一切正常 xff0c 但是启动服务的时候报一下的错误 xff1a root 64 rhsde scripts start
  • Java中swap()方法的实现

    为了能更多的掌握C C 43 43 xff0c 时不时的就会拿起一本什么书看看 昨天又看到了请指针和引用的部分 xff0c 又会有经典的swap 方法的实现 几乎所有人都知道了 xff0c 要实现一个正确的swap 方法需要以指针或引用为参
  • 渐变色原理

    引用 http www islandcn com post 311 html 在图象图形的编程中 经常会见到渐变色以及各种图片的叠加等效果 这篇文章就是要对这些效果的原理加以分析 并在Elastos 操作系统 Mobile Edition
  • JAX-WS 学习二:创建客户端

    上一节中介绍了怎么基于JAX WS的API创建服务端 xff0c 这一节介绍一下创建一个客户端调用WebService服务 要创建一个Client端也相当简单 xff0c 不过需要知道几个东西 xff1a 1 wsdl文件路径 需要读取服务
  • 使用JDI监听Java程序运行

    Java虚拟机提供了一套用于调试 xff08 JVMDI xff09 和监视 xff08 JVMPI xff09 的接口 xff0c Java5之后统一为JVMTI xff1a http docs oracle com javase 1 5
  • 使用CXF和camel-cxf调用webservice

    CXF是什么 Apache CXF 是一个开源的 全功能的WebService框架 xff0c 它提供了一套工具和API来帮助开发和构建WebService xff0c 像 JAX WS 和 JAX RS 它也支持许多WebService标