CXF前端(Frontend)是编程使用的API,用来开发和对外暴露Web Services。CXF提供两种类型的前端(Frontend):JAX-WS和简单前端(Simple Frontend)。本节将详细介绍JAX-WS前端。
JAX-WS前端
Code-First方式
创建Service Endpoint Interface ( SEI)
添加Java注解
发布服务
开发客户端
运行Web Service
JAX-WS前端
CXF支持由Java Community Process (JCP)提供的JAX-WS 2.0 API规范。CXF实现了JAX-WS规范。
JAX-WS提供了两种方式来创建Web Service:Code-First和Contract-First。
Code-First:先创建Java类然后基于Java类生成Web Service组件。一般用于输入/输出对象格式简单,并希望快速部署应用。Code-First的方式正如开发普通的JAVA应用一样,不用关心WSDL和XSD的生成,也不必维护JAVA对象和XML元素的映射关系。只需要在JAVA类中注明,CXF中的工具Java2WSDL会为你完成这些工作。
Contract-First:开发者基于WSDL规范来编写将要暴露的Web Service。Contract-First的方式适用于你已经定义好Web Service操作的输入/输出的消息格式,或者想更好的控制XML与JAVA对象之间的映射关系。Contract-First开发模式要求你精通XSD和WSDL规范。
想更深一步了解请看:《代码优先(Code-First)和契约优先(Contract-First)的比较》
Code-First方式:
Code-First方式需求完成的工作有:
创建Service Endpoint Interface ( SEI)
添加Java注解
发布服务
开发客户端
创建Service Endpoint Interface ( SEI):
Service Endpoint Interface与JAVA Interface类似,定义了业务的服务方法。你可以从零开始开发SEI,或者将现有的业务功能转换为基于服务的组件。
从零开始就是说,没有任何代码或WSDL约束,重新开发Web Service。适用于先创建接口后编写实现代码。将现有代码转换,就是利用已经存在的业务功能,将其转换为基于服务的组件。大部分情况是我们拥有已经实现好的业务逻辑,只是需要将其暴露为Web Service方法。我们可以开发SEI并定义哪些业务方法需要暴露出去,很轻松的实现普通业务到基于服务的转变。
使用《Apache CXF开发Web Service 开发Web Service之Kick Start》中提到的例子。
package demo.order;
import javax.jws.WebService;
@WebService
public interface OrderProcess {
String processOrder(Order order);
}
package demo.order;
import javax.jws.WebService;
@WebService(serviceName="OrderProcessService", portName="OrderProcessPort")
public class OrderProcessImpl implements OrderProcess {
public String processOrder(Order order) {
String orderID = validate(order);
System.out.println("Processed order..." + orderID);
return orderID;
}
/**
* Validates the order and returns the order ID
**/
private String validate(Order order) {
String custID = order.getCustomerID();
String itemID = order.getItemID();
int qty = order.getQty();
double price = order.getPrice();
if (custID != null && itemID != null && !custID.equals("") &&
!itemID.equals("") && qty > 0 && price > 0.0) {
return "ORD1234";
}
return null;
}
}
JAVA注解:
给JAVA类添加Web Service注解后,暴露成服务组件。JAX-WS使用JAVA5注解,使用了Java Platform specification ( JSR-181 ).这些注解用来定义详细的组件和方法。每个注解都拥有一个或多个属性。接下来将讨论一下两个Web Serivce注解:javax.jws.WebService和javax.jws.soap.SOAPBinding。
JAVA组件通过添加@WebService注解来转换为服务。这个注解在SEI和实现类中均需添加。@WebService 注解由javax.jws.WebService接口定义。
@WebService 注解的属性有:Name, targetNamespace, serviceName, wsdlLocation, endpointInterface, portName。
具体解释可参考http://docs.oracle.com/javase/6/docs/api/javax/jws/WebService.html
Attribute |
Description |
Name |
Indicates the name of the service interface. It is directly mapped to a name attribute of the <wsdl:portType> element in WSDL document. If the attribute is not provided, then the name of the service interface is taken as default |
targetNamespace |
It holds the namespace where the service is defined. If no namespace is provided, then the package name is taken as default |
serviceName |
The name of the published service object. It directly maps to a name attribute of wsdl:service element in WSDL document. The default value is the name of the service implementation class. |
wsdlLocation |
It indicates the location of WSDL document in the form of URL |
endpointInterface |
This attribute is used by the service implementation class. It specifies the fully qualified name of the service interface which will be implemented by the service implementation class. |
portName |
It indicates the name of the endpoint where the service is published. It directly maps to a name attribute of the <wsdl:port> element in the WSDL document. |
为OrderProcess SEI 和 OrderProcessImpl添加@WebService注解,如代码中黄色突出部分。值得注意的是,OrderProcessImpl中还有额外的属性
@WebService(serviceName="OrderProcessService", portName="OrderProcessPort")
serviceName被客户端用户获取远端接口存根,调用服务方法。portName指明endpoint的名称。当然剩下的属性也可以使用。这些属性完整的描述服务的细节。建议充分利用这些注解来描述Web Service,这样生成的WSDL文档将会拥有更纤细的内容。如果没有使用这些属性,如OrderProcess SEI一样,WSDL中会默认设置一些值。
@SOAPBinding注解由javax.jws.soap.SOAPBinding接口定义。这个注解用来指定SOAP绑定。
参考http://docs.oracle.com/javase/6/docs/api/index.html?javax/jws/WebService.html
Attribute |
Description |
Default |
Style |
Indicates the style of the SOAP message. The attribute supports two styles, namely, Style.DOCUMENT and Style.RPC. |
The default is DOCUMENT |
Use |
The attribute determines how the SOAP message is to be formatted during serialization. It supports two values, namely, Use.LITERAL and Use.ENCODED |
The default is LITERAL. |
parameterStyle |
Indicates how the SOAP messages are to be used. The message can be either wrapped, that is, operation parameters are wrapped as child elements inside an element in the SOAP body, or it can be unwrapped as different individual elements. It supports two values, namely ParameterStyle.BARE and ParameterStyle.WRAPPED. |
The default is WRAPPED. |
Web Service SOAP通讯方式在SOAP XML消息中起着重要的作用,有两种SOAP通讯样式:Document和RPC。在WSDL文档中由SOAP binding定义。SOAP binding可以有加密的形式或者文本的形式。如:
<soap:binding style="document" transport="uri">
Document样式处理XML文本。在调用过程中,整个文档在服务客户端和服务器之间进行交换,特别是使用XML Schema Definitions (XSD) 创建的XML文本。RPC ( Remote Procedure Call)样式指出SOAP body包含了XML。SOAP规范定义了一系列编码规则,用来将方法参数序列化以便被Web Service实现反序列化调用。在实际使用中尽量使用Document样式。
Document样式的优点:
充分利用XML易读和易扩展的特点,来描述和验证复杂的业务。而RPC执行复杂业务较为繁琐,需要包含XML文档作为参数并在调用方法中做好验证。
修改代码方便。
适用于异步处理,可以直接放到消息队列中。
使用XML交换对象,无需序列化对象。
想更深入了解请阅读《获得文档样式 Web 服务的好处》
一个@SOAPBinding的例子:
@WebService(name="OrderProcess")
@SOAPBinding(parameterSyle=ParameterStyle.BARE)
public interface OrderProcess {
String processOrder(Order order);
}
发布服务:
发布服务意思是将服务组件注册到服务器中,客户端通过endpoint URL访问。CXF提供独立的服务器工具JaxWsServerFactoryBean,这里不做详细介绍。
package demo.order;
import javax.xml.ws.Endpoint;
public class Server {
protected Server() throws Exception {
System.out.println("Starting Server");
OrderProcessImpl orderProcessImpl = new OrderProcessImpl();
String address = "http://localhost:8080/OrderProcess";
Endpoint.publish(address, orderProcessImpl);
}
public static void main(String args[]) throws Exception {
new Server();
System.out.println("Server ready...");
Thread.sleep(5 * 60 * 1000);
System.out.println("Server exiting");
System.exit(0);
}
}
Endpoint类提供了便利的静态方法来发布和测试JAX-WS Web Service。使用Endpoint URL地址和实现的方法作为参数。这个轻量级的服务器会运行5分钟后自动退出。在浏览器中输入如下内容可已看到WSDL文档。
http://localhost:8080/OrderProcess?wsdl
开发客户端:
package demo.order.client;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import demo.order.Order;
import demo.order.OrderProcess;
public class Client {
private static final QName SERVICE_NAME = new QName("http://order.demo/", "OrderProcessService");
private static final QName PORT_NAME = new QName("http://order.demo/", "OrderProcessPort");
private static final String WSDL_LOCATION = "http://localhost:8080/OrderProcess?wsdl";
public static void main(String args[]) throws Exception {
URL wsdlURL = new URL(WSDL_LOCATION);
Service service = Service.create(wsdlURL, SERVICE_NAME);
OrderProcess port = service.getPort(PORT_NAME, OrderProcess.class);
Order order = new Order();
order.setCustomerID("C001");
order.setItemID("I001");
order.setPrice(100.00);
order.setQty(20);
String result = port.processOrder(order);
System.out.println("The order ID is " + result);
}
}
WSDL URL指明为http://localhost:8080/OrderProcess?wsdl
接着创建Service对象。使用Service的静态方法create来创建。服务的名称为OrderProcessService。将在WSDL文档中映射为<wsdl:service name="OrderProcessService">。
然后使用Service对象,通过getPort方法获取SEI存根代码组件。Endpoint的名称为OrderProcessPort。将在WSDL文档中映射为<wsdl:port binding="tns:OrderProcessServiceSoapBinding" name="OrderProcessPort">。
最后使用代理的组件port调用processOrder方法。
运行Web Service
这里使用Maven来作为构建工具。如果想立刻看到效果请使用NetBean,内置了Maven。如果使用eclipse则需要添加m2eclipse插件,参见Eclipse 的 Maven 插件 m2eclipse。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dcb.cxfbook.ch03</groupId>
<artifactId>codefirst2</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>codefirst</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cxf.version>2.2.3</cxf.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-xjc</artifactId>
<version>2.1.12</version>
</dependency>
</dependencies>
<build>
<finalName>codefirst</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>server</id>
<build>
<defaultGoal>test</defaultGoal>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>demo.order.Server</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>client</id>
<build>
<defaultGoal>test</defaultGoal>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>demo.order.client.Client</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
pom.xml中,添加cxf-rt-frontend-jaxws,cxf-rt-transports-http和cxf-rt-transports-http-jetty(发布服务是需要)依赖,maven会自动加载相关的jar包,包括CXF, Spring, common, JABX, jetty。在profiles. Profile. Build. Plugins. Plugin节点添加exec-maven-plugin提供通过-Pserver和-Pclient来界定命令行运行demo.order.Server 和demo.order.client.Client。
cd codefirst2
#启动server,显示Server ready...消息
mvn test –Pserver
#执行client,显示The order ID is ORD1234
mvn test -Pclient
也可以在在IDE (Netbean or Eclipse)中直接执行运行。先执行Server,后执行Client。
名词解释:
XML Schema Definition (XSD) XML Schema描述了XML文档的结构。可以用一个指定的XML Schema来验证某个XML文档,以检查该XML文档是否符合其要求。文档设计者可以通过XML Schema指定一个XML文档所允许的结构和内容,并可据此检查一个XML文档是否是有效的。XML Schema本身是一个XML文档,它符合XML语法结构。可以用通用的XML解析器解析它。
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
参考内容:
http://baike.baidu.com/view/712698.htm XSD 百科
http://baike.baidu.com/view/160660.htm WSDL百科
http://jcp.org/en/jsr/detail?id=181 JSR-181
http://baike.baidu.com/view/2742297.htm CXF百科
http://baike.baidu.com/view/160660.htm WSDL百科
http://baike.baidu.com/view/60663.htm SOAP百科
http://baike.baidu.com/view/32726.htm RPC 百科