Apache CXF WebService 分布式跨域调用
一.Apache CXF 介绍
Apache CXF 是一个开放源代码框架,提供了用于方便地构建和开发 Web 服务的可靠基础架构。它允许创建高性能和可扩展的服务,您可以将这样的服务部署在 Tomcat 和基于 Spring 的轻量级容器中,以及部署在更高级的服务器上,例如 Jboss、IBM® WebSphere® 或 BEA WebLogic。
二.Apache CXF 下载
Apache官网提供下载地址: http://mirrors.cnnic.cn/apache/cxf/ 我这里选择了3.0.11版本
三.接下来我们新建一个web Project项目。项目名叫cxfWebPrj。
将我们之前下载下的CXF包解压,将lib目录下的jar文件拷贝到项目WEB—INFO/lib目录下。这是该项目所需的jar,这类jar包含了cxf的服务包,jetty服务的支持以及spring的相关jar包。具体的应用我还没分包。
四.首先新建一个接口 和 实现类
package com.zhj.servers; import javax.jws.WebService; @WebService public interface CxfInterface { public String sayHello(String name); }
package com.zhj.servers.impl; import javax.jws.WebService; import javax.xml.ws.Endpoint; import com.zhj.servers.CxfInterface; @WebService(endpointInterface="com.zhj.servers.CxfInterface",serviceName="CxfInterface",targetNamespace="http://servers.zhj.com/") public class CxfWebServerImpl implements CxfInterface{ @Override public String sayHello(String name) { // TODO Auto-generated method stub return "hello " + name; } public static void main(String[] args) { System.out.println("web service start"); CxfInterface implementor= new CxfWebServerImpl(); String address="http://localhost:8081/webPrj1"; Endpoint.publish(address, implementor); System.out.println("web service started"); } }
五.建立一个客户端类,调用服务接口。
package com.zhj.client; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import com.zhj.servers.CxfInterface; public class CxfClientTest { public static void main(String[] args) { JaxWsProxyFactoryBean svr = new JaxWsProxyFactoryBean(); svr.setServiceClass(CxfInterface.class); svr.setAddress("http://localhost:8081/webPrj1"); CxfInterface hw = (CxfInterface) svr.create(); System.out.println(hw.sayHello("zhjtest")); } }
六.先启动服务端的main方法。在执行客户端的方法。
简单的测试过程,是利用jetty服务发布的webService,比较便捷的是服务地址可自由定制,我自行约定服务地址:http://localhost:8081/webPrj1
相对于的客户端也通过该地址调用接口访问,比Axis2较为方便灵活。
-----------------------------------------------------------------------------------------------------------------------------------------------------------
下面介绍与spring结合发布服务及调用。
一.WEB-INFO目录下新建spring配置文件:applicationContext.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:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.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" /> --> <!--<jaxws:endpoint id="helloWorld" implementor="com.zhj.servers.impl.CxfWebServerImpl" address="/CxfInterface1" /> id:定义的别名 implementor:实现类的接口路径; (address:是指定发布接口的名称,可以和接口定义的名称不同) --> <jaxws:endpoint id="helloWorld" implementor="com.zhj.servers.impl.CxfWebServerImpl" address="/testCxf" /> <bean id="client" class="com.zhj.servers.CxfInterface" factory-bean="factorybean" factory-method="create"/> <bean id="factorybean" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> <property name="serviceClass" value="com.zhj.servers.CxfInterface"/> <property name="address" value="http://localhost:8080/cxfWebPrj/webservice/testCxf"/> </bean> </beans>
在这段配置里,我需要说明,咱们发布的服务地址是该配置文件暴露的。其中
1.<jaxws:endpoint id="helloWorld" implementor="com.zhj.servers.impl.CxfWebServerImpl" address="/testCxf" /> 其中address的名称,可自行定义。
2.<property name="address" value="http://localhost:8080/cxfWebPrj/webservice/testCxf"/> 但是最后暴露的服务地址必须指向该定义的地址名称,其中cxfWebPrj为本项目名称,这与jetty发布的服务不同,不能随意改动。
3.DDT 必须要引入cxf地址
xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs"
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
spring就不用说了,毫无疑问要加上。
二.配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name>My Web Application</display-name> <!-- location of spring xml files --> <!-- <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:camel-config.xml</param-value> </context-param> --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- CXF servlet --> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> <!-- If you want to leverage the Servlet3's async feature in Tomcat, please enable this feature <async-supported>true</async-supported> --> </servlet> <!-- all our webservices are mapped under this URI pattern 必须指定成/webservice/*--> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/webservice/*</url-pattern> </servlet-mapping> </web-app>
web.xml配置主要是指定spring配置的路径,还有配置cxf Servlet映射。
三.新建一个客户端调用:
package com.zhj.client; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.zhj.servers.CxfInterface; public class CxfSpringClientTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("file:WebRoot/WEB-INF/applicationContext.xml"); CxfInterface client = (CxfInterface)context.getBean("client"); System.out.println(client.sayHello("zhj")); } }
其中 context.getBean("client"); client 是applicationContext.xml 中配置的bean。
四.部署项目,启动服务。然后在客户端运行CxfSpringClientTest类。
-----------------------------------------------------------------------------------------------------------------------------------------------------------
接下来,我贴近大部分业务需要说下cxf webService分布式跨域调用.
cxf 服务还是使用上面所写的webService 服务实现。
在另一个web项目中,新建一个webServiceClient类,采用动态调用方式 如下:
package com.ywkj.action.webServiceClient; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.namespace.QName; import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.ywkj.action.BaseAction; @Controller public class WebServiceClient extends BaseAction { //webService服务地址 private static final String WSDL_URL = "http://127.0.0.1:8080/cxfWebPrj/webservice/testCxf?wsdl"; @RequestMapping(value = "web/webServerTest") public void callWebServertoCommand(HttpServletRequest request, HttpServletResponse response){ JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); Client client = dcf.createClient(WSDL_URL); //指定到接口类所在包 ,sayHello 为接口中定义的方法名称 张三为传递的参数 返回一个Object数组 QName opName = new QName("http://servers.zhj.com/","sayHello"); Object[] objects = null; try { objects = client.invoke(opName, "张三"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //输出调用结果 System.out.println(objects[0].toString()); } }
编写前端调用方法(此处省略前端调用代码),调用该callWebServertoCommand的Action方法。我这里输出了,调用webService服务返回的字符串
在客户端调用需要引入两个jar包
需要注意的是:QName 类实例化时,第一个参数 namespaceURI 是包反序列的路径,这是Java定义的规范。第二参数,是你要调用的方法名。然后用cxf 自带的client 反射调用webService方法。
至此,简单的cxf服务端发布和客户端调用以及分布式跨域调用已全部实现,如有不合理之处请小伙伴指点出来,thank you!