如今開發的一個項目要求使用Mule ESB爲一個已有的系統的Web Service接口作代理接口,客戶端調用原來Web Service接口的代碼要求不作大的改動,只修改調用Web Service的url地址爲Mule ESB代理接口的url地址。html
這個要求看起來很簡單,可是實現起來發現有兩個問題:java
1)如何經過Mule ESB的Http控件暴露已有Web Service接口的描述文件?web
也就是說原來描述文件的地址是http://[target ip]:[target port]/service?wsdl,通過http控件後將變成spring
http://[new ip]:[new port]/newservice?wsdl,並且wsdl文件的內容不能改變。apache
2)如何將Mule ESB接口接收的Soap報文發送到實際的Web Service地址,獲得實際結果。服務器
第一個問題我使用CXF Component組件的Proxy Service類型進行配置。app
我建立了兩個Web Service服務,一個是使用Apache CXF搭建的Web Service,一個是使用Asp.net搭建的Web Servicejsp
使用Apache CXF搭建的Web Service只有一個HelloService,主要的類文件和配置文件以下:ide
package com.rick.service; import javax.jws.WebParam; public interface HelloService { String sayHello(@WebParam(name="name") String name); }
package com.rick.service.impl; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; import org.springframework.stereotype.Component; import com.rick.service.HelloService; @Component("helloService") @WebService public class HelloServiceImpl implements HelloService { @Override @WebMethod(action="sayHello") public String sayHello(@WebParam(name="name") String name) { return "Hello world," +name; } }
applicationContext.xmlurl
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <!-- import CXF configuration files --> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/> <context:component-scan base-package="com.rick.service" /> <jaxws:endpoint implementor="#helloService" address="hello"/> </beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>WsDemo</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- Spring listener --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/webservice/*</url-pattern> </servlet-mapping> </web-app>
Web Service配置在一個Web Application中,在Eclipse EE的Tomcat Server啓動後的Web Service wsdl文件訪問地址是:
http://localhost:8080/WsDemo/webservice/hello?wsdl
具體內容以下圖所示
咱們新建一個Mule Project項目WsDemoProxy
在WsDemoProxy項目中,拖拽一個Http Listener和CXF Component組件
Http Listener組件是入口,配置以下圖所示
Http訪問端口爲8081,訪問Path爲/wsdemoproxy
CXF Component配置爲Proxy Service,配置以下圖所示
其中Namespace使用wsdl文件的targetNamespace值,Service使用wsdl:service節點的name屬性值。
在[Advanced] Tab中設置實際的WSDL地址,這裏可使用在線的wsdl地址,也可使用本地的wsdl文件地址,本項目使用前者。
啓動WsDemoProxy項目,訪問http://localhost:8081/wsdemoproxy?wsdl,咱們能夠看到顯示WsDemo項目的wsdl描述文件,代表使用CXF Component 代理CXF搭建的Web Service wsdl成功。
我使用Visual Studio 2008建立一個Asp.net Web Service
這個Web Service服務有兩個方法,HelloWorld()和addMethod(int, int),咱們設置它的啓動端口爲8888,啓動後界面以下:
對應的wsdl界面以下:
新建一個Mule ESB項目webservice1proxy,與wsdemoproxy同樣,一樣拖拽一個Http Listener和CXF Component控件。兩個控件配置以下圖所示
Http Listener使用的端口號仍是8081
須要指出的是,因爲Asp.net搭建的web service服務器有Soap1.1和Soap1.2兩種協議形式,所以在CXF Proxy Service中必須指定Binding id,即wsdl中的wsdl:binding節點的name屬性,因爲咱們使用Soap1.1協議,所以Binding Id使用1.1協議對應的ServiceSoap1.
啓動webservice1proxy項目,訪問http://localhost:8081/webservice1proxy?wsdl,顯示webservice1的wsdl描述文件。
在代理Web Service的wsdl文件成功後,接下來解決第二個問題,即經過Mule ESB轉發Web Service請求到真實的Web Service請求,得到結果返回調用客戶端,咱們經過在Mule ESB項目中使用Web Service Consumer來實現,下文咱們將詳細說明。
啓動WsDemo項目,咱們在SoapUI中調用這個Web Service,以下圖所示
在WsDemoProxy項目中拖一個Web Service Consumer組件,配置它指向WsDemo的wsdl文件
加載wsdl文件後,Service,Port和Address將自動掃描wsdl文件獲取。
在Operation行的下拉列表中選擇要調用的Web Service方法(這裏只有sayHello方法)
保存後啓動WsDemoProxy項目,再使用SoapUI調用WsDemoProxy代理的Web Service,以下圖所示
和直接調用WsDemo的結果徹底同樣。
使用CXF Client客戶端調用
import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; public class WebServiceClientDemo { public static void main(String[] args) throws Exception { JaxWsDynamicClientFactory clientFactory = JaxWsDynamicClientFactory.newInstance(); Client client = (Client) clientFactory.createClient("http://localhost:8081/wsdemoproxy?wsdl"); Object[] result = client.invoke("sayHello","Rick"); if(result != null && result.length > 0) { System.out.println(result[0].toString()); } } }
返回結果以下圖所示
使用.net客戶端進行調用
首先創建一個ServiceReference指向WsDemo Web Service
而後在代碼裏引用生成的代理類HelloServiceImplClient
namespace WebServiceClient { public class Program { public static void Main(string[] args) { WsDemoReference.HelloServiceImplClient client = new WsDemoReference.HelloServiceImplClient(); Console.WriteLine(client.sayHello("Rick")); } } }
執行結果以下圖所示(按Ctrl + F5啓動程序,不然Console窗口會一閃而過)
同2.1,咱們修改webservice1proxy項目,因爲WebService1暴露了兩個方法,咱們須要加入兩個Web Service Consumer控件