引言: 在跨系统和跨平台的系统通信中,WebService是一个事实上的标准,其以平台无关性,获得了广泛的应用。本文将讲述如何基于Spring来集成CXF,并开发出第一个Hello World的应用。
1. Web Service是什么?
Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。
Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。Web Service是自描述、 自包含的可用网络模块, 可以执行具体的业务功能。Web Service也很容易部署, 因为它们基于一些常规的产业标准以及已有的一些技术,诸如标准通用标记语言下的子集XML、HTTP。Web Service减少了应用接口的花费。Web Service为整个企业甚至多个组织之间的业务流程的集成提供了一个通用机制。
2. Web Service模型
WebService体系结构基于三种角色(即服务提供者、服务注册中心和服务请求者)之间的交互。交互涉及发布、查找和绑定操作,这些角色和操作一起作用于WebServices组件,即WebServices软件模块及其描述。在典型情况下,服务提供者托管可通过网络访问的的软件模块,定义WebServices的服务描述并把它发布到服务注册中心;服务请求者使用查找操作来从服务注册中心检索服务描述,然后使用服务描述与服务提供者进行绑定并调用WebServices实现和同它交互。
面向服务的体系结构(SOA),如图所示:
从图中可以看出,SOA结构中共有三种角色:
(1)、服务提供者:发布自己的服务,并且对服务请求进行响应。
(2)、服务注册中心:注册已经发布的WebServices,对其进行分类,并提供搜索服务。
(3)、服务请求者:利用服务注册中心查找所需的服务,然后使用该服务。
SOA体系结构中的组件必须具有上述一种或多种角色,这些角色之间使用三种操作:
(1)、发布操作:使服务提供者可以向服务注册中心注册自己的功能及访问接口。
(2)、查找操作:使服务请求者可以通过服务注册中心查找特定种类的服务。
(3)、绑定操作:使服务请求者能够真正使用服务提供者提供的服务。
3. WebService开源框架的选择
目前主流的Web Service框架主要有3种: Axis 2, CXF, 和 Spring WS。其中Spring WS出身Spring框架,名门出身,但是使用了几次,太关注于标准支持,比较难以使用。
Axis 2和CXF都是来自于Apache, 各个方面相差不多,但是考虑到目前市场上使用CXF比较多一点,就才用了CXF。
4. 基于CXF创建WebService
项目背景是Spring 3.2, CXF: 2.7.14,JDK 1.6, Maven 3.2.3.
4.1 在POM.xml中添加正确的依赖包。
<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>注意: 第二个http的包必须进行添加,否则会报错。
4.2 创建服务接口
@WebService public interface IHelloWorld { @WebMethod public String sayHello(@WebParam(name = "username") String username); public void setUser(String username); }
注意:“@WebService”标记表示该接口是一个WebService服务;“@WebMethod”表示表示以下方法为WebService服务中的方法;“@WebParam(name="username")”表示方法中的参数,username属性限制了参数的名称,若没有指定该属性,参数将被重命名。
4.3 创建服务实现类
public class HelloWorldImpl implements IHelloWorld { @Override public String sayHello(String username) { return "Hello " + username; } @Override public void setUser(String username) { } }4.4 在Web.xml中声明CXF监听器
<servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/webservice/*</url-pattern> </servlet-mapping>注意:<servlet-mapping>下的<url-pattern>指明了服务访问地址的形式,“/*”代表URL地址中,包名称后直接跟服务endpoint地址,若指明<url-pattern>为/webservice/*,则URL为“包名/webservice/endpoing?wsdl”。
4.5 创建WebService声明的Spring配置文件spring-cxf-service.xml
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:http-conf = "http://cxf.apache.org/transports/http/configuration" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="helloServiceBean" class="com.creditease.bsettle.webservice.HelloWorldImpl" /> <!-- 第一个测试级WebService服务发布 --> <jaxws:endpoint id="helloService" implementor="helloServiceBean" address="/helloService" /> <!-- 转账相关service(换一种服务发布方式) --> <jaxws:server id="CeTransferAccountWS" address="/CeTransferAccountWS" xmlns:s="http://impl.ce.handler.transferaccount.payplatform.app.creditease.com/"<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
<span style="font-family: Arial, Helvetica, sans-serif;"> serviceClass="com.creditease.ns.adapter.transfer.CeTransferAccountWS"> </span>
<span style="font-family: Arial, Helvetica, sans-serif;"> <jaxws:serviceBean></span>
<bean class="com.creditease.ns.adapter.transfer.impl.CeTransferAccountWSImpl" /> </jaxws:serviceBean> </jaxws:server> </beans>注意:<jaxws:endpoint>定义了一个WebService,implementor是WebService处理类,值为在(6)中定义的bean的id,其具体的实现类在class中指明,address是它的访问路径,就是上面提到的将要在URL中显示的endpoint的名称。
4.6 spring配置文件在web.xml中的位置
由于在web.xml中配置了listener, 所以需要将该配置文件读入的位置提前,不能放在DispatcherServlet的配置文件路径中。问题参照7.2.
<!-- The definition of the Root Spring Container shared by all Servlets and Filters --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:META-INF/spring-hibernate.xml classpath:META-INF/spring-cxf-service.xml </param-value> </context-param>
4.6 测试Web Service
访问路径: http://host:port/context_path/services,获取该路径所有的服务列表
读取wsdl文件内容,访问路径: http://host:port/context_path/services/serviceName?wsdl
4.7 基于SoapUI进行接口测试
5. 创建CXF客户端
正常开发两个独立系统之间互操作的服务,需要双方协商好WSDL,然后根据WSDL规范去实现互操作性。在本示例中,我们已经开发完成了服务端程序,下面需要开发客户端程序,为了达到客户端调用服务端的目的,我们需要通过双方协商好的WSDL(这里直接通过访问服务端服务地址得到)来生成Java存根类文件。
CXF发行版提供了一个名为“wsdl2java.bat”的工具,该工具可以通过WSDL为特定的服务创建stub。该工具有如下参数:
-p : 指定其wsdl的命名空间,即要生成代码的包名。 -d : 指定要产生代码所在目录。 -client : 生成客户端测试web service的代码。 -server : 生成服务器启动web service的代码。 -impl : 生成web service的实现代码。 -ant : 生成build.xml文件。 -compile : 生成代码后编译。 -quient : 静默模式,不输出警告与错误信息。 -all : 生成所有开始端点代码:types, service proxy, service interface, server mainline, client mainline, implementation object, and an Ant build.xml file。 |
一般用到的命令:“wsdl2java –p 生成代码的包名–d 生成代码的路径 wsdl地址”。执行命令生成本示例的stub代码文件:
也可以利用Java自带的方式生成WS客户端文件:
D:\Program Files\Java\jdk1.6.0_26\bin>wsimport -sD:/workspaceNew/shortcutDemo/s
rc/com/creditease/ns/adapter/channel/implhttp://10.100.30.37:8089/ns-adapter-ch
annel/services/CeFinalPaymentWS?wsdl
D:\apache-cxf-2.7.6\bin>wsdl2java.bat -pcom.creditease.ns.adapter.channel.impl
-dD:/workspaceNew\shortcutDemo/src/com/creditease/ns/adapter/channel/impl http:
//10.100.30.37:8089/ns-adapter-channel/services/CeFinalPaymentWS?wsdl
6. 编写客户端测试类,模拟调用服务
第一种实现方式:通过JaxWsProxyFactoryBean代理类来设定服务处理类和服务地址,无须额外的客户端配置。
package com.test.client; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; /** * 客户端测试服务调用 * * @author Administrator * */ public class MainTestClient { public static void main(String[] args)throws Exception { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(IServerService.class); factory.setAddress("http://localhost:8080/workflow/webservice/sayHello?wsdl"); IServerService client = (IServerService) factory.create(); String response = client.sayHello("Hai,jiangqiao"); System.out.println("Response:" + response); } } |
注意:此种方式比较方便,无须配置比较灵活,大部分情况下都会采用这种方式调用服务程序。
运行客户端程序,调用成功并能正常反馈,说明客户端与服务端的一次交互成功!
第二种实现方式:通过配置客户端来调用服务,方式比较麻烦需要额外对客户端进行配置,这里只需要了解下即可。
<jaxws:clientid="sayHello2" serviceClass="com.test.client.IServerService" address="http://localhost:8080/workflow/webservice/sayHello?wsdl"/> |
说明:该方式访问ws服务是利用了Spring的依赖注入法,其中id是Spring IOC容器唯一标识符,在代码中也是通过id获取服务对象的(context.getBean("sayHello2"));serviceClass是WebService服务接口;address是WDSL地址。
按照此种方式额外配置客户端信息之后,客户端代码则写成这样:
public testWebService() throws Exception IServerService client =(IServerService)CrmContexts.getBean("sayHello2"); String response = client.sayHello("Hai,jiangqiao"); System.out.println("Response:" + response); } |
实际上这种方式与第一种方式在过程上是一致的,都是设定服务处理类和WDSL地址的过程,只不过方式不一样。可以根据项目的不同设计而进行选择!
注意,此种方式配置客户端,必须通过HTTP的方式进行访问才能正常调用服务,否则会报Spring找不到相应对象的错误;这种访问方式的好处就是,不需要生成桩文件。
7. . 问题以及解决
7.1 No bean named ‘cxf‘ is defined
错误信息如下:
HTTP Status 500 - Servlet.init() for servlet CXFService threw exception type Exception report message Servlet.init() for servlet CXFService threw exception description The server encountered an internal error that prevented it from fulfilling this request. exception javax.servlet.ServletException: Servlet.init() for servlet CXFService threw exception org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2441) org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2430) java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) java.lang.Thread.run(Thread.java:662) root cause org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cxf' is defined org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:575) org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1111) org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:276) org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195) org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1121) org.apache.cxf.transport.servlet.CXFServlet.loadBus(CXFServlet.java:80) org.apache.cxf.transport.servlet.CXFNonSpringServlet.init(CXFNonSpringServlet.java:76) org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2441) org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2430) java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) java.lang.Thread.run(Thread.java:662) note The full stack trace of the root cause is available in the Apache Tomcat/7.0.53 logs.原因以及解决办法:
主要的原因是cxf对象实例初始化顺序晚于CXFServlet, 故需要将其spring-cxf-service.xml的初始化顺序从原来的dispatcherServlet, 提前至<context-param>中的初始化参数
7.2 class path resource [META-INF/cxf/cxf-servlet.xml] cannot be opened because it does not exist
完整的错误日志信息如下:
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [spring-cxf-service.xml] Offending resource: class path resource [META-INF/applicationContext.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath:META-INF/cxf/cxf-servlet.xml] Offending resource: class path resource [META-INF/spring-cxf-service.xml]; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [META-INF/cxf/cxf-servlet.xml]; nested exception is java.io.FileNotFoundException: class path resource [META-INF/cxf/cxf-servlet.xml] cannot be opened because it does not exist at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68) at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85) at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:282) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(DefaultBeanDefinitionDocumentReader.java:207) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:192) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:139) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:108) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4973) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:662) Caused by: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath:META-INF/cxf/cxf-servlet.xml] Offending resource: class path resource [META-INF/spring-cxf-service.xml]; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [META-INF/cxf/cxf-servlet.xml]; nested exception is java.io.FileNotFoundException: class path resource [META-INF/cxf/cxf-servlet.xml] cannot be opened because it does not exist at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68) at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85) at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:256) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(DefaultBeanDefinitionDocumentReader.java:207) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:192) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:139) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:108) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:266) ... 29 more Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [META-INF/cxf/cxf-servlet.xml]; nested exception is java.io.FileNotFoundException: class path resource [META-INF/cxf/cxf-servlet.xml] cannot be opened because it does not exist at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:341) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:250) ... 38 more Caused by: java.io.FileNotFoundException: class path resource [META-INF/cxf/cxf-servlet.xml] cannot be opened because it does not exist at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:171) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:328) ... 42 more Jan 21, 2015 11:51:21 AM org.apache.catalina.core.StandardContext startInternal SEVERE: Error listenerStart Jan 21, 2015 11:51:21 AM org.apache.catalina.core.StandardContext startInternal SEVERE: Context [/bsettle] startup failed due to previous errors Jan 21, 2015 11:51:21 AM org.apache.catalina.core.ApplicationContext log INFO: Closing Spring root WebApplicationContext Jan 21, 2015 11:51:21 AM org.apache.catalina.core.StandardContext listenerStop SEVERE: Exception sending context destroyed event to listener instance of class org.springframework.web.context.ContextLoaderListener java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext at org.springframework.context.support.AbstractRefreshableApplicationContext.getBeanFactory(AbstractRefreshableApplicationContext.java:171) at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1090) at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1064) at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:1010) at org.springframework.web.context.ContextLoader.closeWebApplicationContext(ContextLoader.java:586) at org.springframework.web.context.ContextLoaderListener.contextDestroyed(ContextLoaderListener.java:143) at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:5014) at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5659) at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:160) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:662) Jan 21, 2015 11:51:21 AM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["http-bio-7080"] Jan 21, 2015 11:51:21 AM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["ajp-bio-8009"] Jan 21, 2015 11:51:21 AM org.apache.catalina.startup.Catalina start INFO: Server startup in 4258 ms原因以及应对办法:
问题的起源是缺少了jar,关于通信协议和servlet声明的包。引入jar即可,比如在pom.xml中加入如下配置,而非单纯cxf包。
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version> </dependency>8. 总结
CXF在实现上存在诸多的底层实现,jaxws, rs等等诸多的内容,这里只选取jaxws来做为示例,至于其他的诸多实现,笔者也不是非常熟悉,姑且放下不论。好了,经过了漫长的配置和调试之后,相信大家对于如何使用cxf进入开发状态有了一个初步的认识。
目前来说,越来越多的企业和系统已经迁移至基于http请求的json或者xml格式的请求,而非标准的soap/webservice请求,究其原因还是soap/webservice过于复杂、标准虽好,但是用着不多。关键是看是否简单易用,可以快速解决开发中存在的问题,在这个方面json/xml则是非常的简单。
参考资料
1. WebService定义 http://baike.baidu.com/link?url=mep-1agA29j5jauITgTP9Hn_iI1X6bM6m0N_D83eflzvNlXmXrVrNMJMV7k3nMunD88qDBkXKOhzUa9kMvslkK
2. 官方站点: cxf.apache.org
基于Maven在Spring中集成CXF Web Service框架
原文地址:http://blog.csdn.net/blueheart20/article/details/42971713