第一篇:java 調(diào)用webservice的各種方法總結(jié)
一、利用jdk web服務(wù)api實(shí)現(xiàn),這里使用基于 SOAP message 的 Web 服務(wù)
1.首先建立一個Web services EndPoint:
Java代碼
package Hello;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.xml.ws.Endpoint;
@WebService
public class Hello {
@WebMethod
public String hello(String name){
return “Hello, ” + name + “n”;}
public static void main(String[] args){
// create and publish an endpoint
Hello hello = new Hello();
Endpoint endpoint Endpoint.publish(“http://localhost:8080/hello”, hello);
} }
=
2.使用 apt 編譯 Hello.java(例:apt-d [存放編譯后的文件目錄] Hello.java),會生成 jaws目錄
3.使用java Hello.Hello運(yùn)行,然后將瀏覽器指向http://localhost:8080/hello?wsdl就會出現(xiàn)下列顯示
4.使用wsimport 生成客戶端
使用如下:wsimport-p.-keep http://localhost:8080/hello?wsdl
5.客戶端程序:
Java代碼
1.class HelloClient{ 2.3.public static void main(String args[]){ 4.5.HelloService service = new HelloService();6.7.Hello helloProxy = service.getHelloPort();8.9.String hello = helloProxy.hello(“你好”);10.11.System.out.println(hello);12.13.} 14.15.} 16.二、使用xfire,我這里使用的是myeclipse集成的xfire進(jìn)行測試的
利用xfire開發(fā)WebService,可以有三種方法:
1一種是從javabean 中生成;
一種是從wsdl文件中生成;
還有一種是自己建立webservice
步驟如下:
用myeclipse建立webservice工程,目錄結(jié)構(gòu)如下:
首先建立webservice接口,代碼如下:
Java代碼
1.package com.myeclipse.wsExample;2.3.//Generated by MyEclipse 4.5.6.7.public interface IHelloWorldService { 8.9.10.11.public String example(String message);12.13.14.15.} 16.Java代碼
1.package com.myeclipse.wsExample;2.3.//Generated by MyEclipse 4.5.6.7.public class HelloWorldServiceImpl implements IHelloWorldService { 8.9.10.11.public String example(String message){ 12.13.return message;14.15.} 16.17.18.19.} 20.修改service.xml 文件,加入以下代碼:
Xml代碼
1.2.3.
客戶端實(shí)現(xiàn)如下:
Java代碼
1.package com.myeclipse.wsExample.client;2.3.import java.net.MalformedURLException;4.5.import java.net.URL;6.7.8.9.import org.codehaus.xfire.XFireFactory;10.11.import org.codehaus.xfire.client.Client;12.13.import org.codehaus.xfire.client.XFireProxyFactory;14.15.import org.codehaus.xfire.service.Service;16.17.import org.codehaus.xfire.service.binding.ObjectServiceFactory;18.19.20.21.import com.myeclipse.wsExample.IHelloWorldService;22.23.24.25.public class HelloWorldClient { 26.27.public static void main(String[] args)throws MalformedURLException, Exception { 28.29.// TODO Auto-generated method stub 30.31.Service s=new ObjectServiceFactory().create(IHelloWorldService.class);32.33.XFireProxyFactory xf=new XFireProxyFactory(XFireFactory.newInstance().getXFire());34.35.String url=“http://localhost:8989/HelloWorld/services/HelloWorldService”;36.37.38.39.try 40.41.{ 42.43.44.45.IHelloWorldService hs=(IHelloWorldService)xf.create(s,url);46.47.String st=hs.example(“zhangjin”);48.49.System.out.print(st);50.51.} 52.53.catch(Exception e)54.55.{ 56.57.e.printStackTrace();58.59.} 60.61.} 62.63.64.65.} 66.這里再說點(diǎn)題外話,有時候我們知道一個wsdl地址,比如想用java客戶端引用.net 做得webservice,使用myeclipse引用,但是卻出現(xiàn)無法通過驗(yàn)證的錯誤,這時我們可以直接在類中引用,步驟如下:
Java代碼
1.public static void main(String[] args)throws MalformedURLException, Exception { 2.3.// TODO Auto-generated method stub 4.5.Service s=new ObjectServiceFactory().create(IHelloWorldService.class);6.7.XFireProxyFactory xf=new XFireProxyFactory(XFireFactory.newInstance().getXFire());8.9.10.11.//遠(yuǎn)程調(diào)用.net開發(fā)的webservice 12.13.Client c=new Client(new URL(“http://004km.cn/axis2/
同理,也需要將axis2復(fù)制到webapp目錄中
在axis2中部署webservice有兩種方法,第一種是pojo方式,這種方式比較簡單,但是有一些限制,例如部署的類不能加上包名
第二種方式是利用xml發(fā)布webservice,這種方法比較靈活,不需要限制類的聲明
下面分別說明使用方法:
1.pojo方式:在Axis2中不需要進(jìn)行任何的配置,就可以直接將一個簡單的POJO發(fā)布成WebService。其中POJO中所有的public方法將被發(fā)布成WebService方法。先實(shí)現(xiàn)一個pojo類:
Java代碼
1.public class HelloWorld{ 2.3.public String getName(String name)4.5.{ 6.7.return ”你好 “ + name;8.9.} 10.11.public int add(int a,int b)12.13.{ 14.15.return a+b;16.17.} 18.19.} 20.由于這兩個方法都是public類型,所以都會發(fā)布成webservice。編譯HelloWorld類后,將HelloWorld.class文件放到%tomcat%webappsaxis2WEB-INFpojo目錄中(如果沒有pojo目錄,則建立該目錄),然后打開瀏覽器進(jìn)行測試:
輸入一下url:
http://localhost:8080/axis2/services/listServices
會列出所有webservice
這是其中的兩個webservice列表,接著,在客戶端進(jìn)行測試:
首先可以寫一個封裝類,減少編碼,代碼如下:
Java代碼
1.package MZ.GetWebService;2.3.import javax.xml.namespace.QName;4.5.6.7.import org.apache.axis2.AxisFault;8.9.import org.apache.axis2.addressing.EndpointReference;10.11.import org.apache.axis2.client.Options;12.13.import org.apache.axis2.rpc.client.RPCServiceClient;14.15.16.17.18.19.public class GetWSByAxis2 { 20.21.private static String EndPointUrl;22.23.private static String QUrl=”http://ws.apache.org/axis2“;
24.25.private QName opAddEntry;26.27.public String WSUrl;28.29.public RPCServiceClient setOption()throws AxisFault 30.31.{ 32.33.RPCServiceClient serviceClient = new RPCServiceClient();34.35.Options options = serviceClient.getOptions();36.37.EndpointReference targetEPR = new EndpointReference(WSUrl);38.39.options.setTo(targetEPR);40.41.return serviceClient;42.43.} 44.45.46.47.public QName getQname(String Option){ 48.49.50.51.return new QName(QUrl,Option);52.53.} 54.55.//返回String 56.57.public String getStr(String Option)throws AxisFault 58.59.{ 60.61.RPCServiceClient serviceClient =this.setOption();62.63.64.65.opAddEntry =this.getQname(Option);66.67.68.69.String str =(String)serviceClient.invokeBlocking(opAddEntry, 70.71.new Object[]{}, new Class[]{String.class })[0];72.73.return str;74.75.} 76.77.// 返回一維String數(shù)組 78.79.public String[] getArray(String Option)throws AxisFault
80.81.{ 82.83.RPCServiceClient serviceClient =this.setOption();84.85.86.87.opAddEntry =this.getQname(Option);88.89.90.91.String[] strArray =(String[])serviceClient.invokeBlocking(opAddEntry, 92.93.new Object[]{}, new Class[]{String[].class })[0];94.95.return strArray;96.97.} 98.99.//從WebService中返回一個對象的實(shí)例
100.101.public Object getObject(String Option,Object o)throws AxisFault 102.103.{ 104.105.RPCServiceClient serviceClient =this.setOption();106.107.QName qname=this.getQname(Option);108.109.Object object = serviceClient.invokeBlocking(qname, new Object[]{},new Class[]{o.getClass()})[0];110.111.return object;112.113.} 114.115.116.117.///////////////////////////////////////// 讀者可以自己封裝數(shù)據(jù)類型,如int,byte,float等數(shù)據(jù)類型
118.119.} 120.客戶端調(diào)用方法:
Java代碼
1.MZ.GetWebService.GetWSByAxis2 ws=new MZ.GetWebService.GetWSByAxis2();2.3.ws.WSUrl=”http://localhost:8989/axis2/services/HelloWorld“;4.5.HelloWorld hello=(HelloWorld)ws.getObject(”getName“, HelloWorld.class);6.7.8.9.10.11.System.out.println(hello.getName(”zhangjin“));12.2.使用service.xml發(fā)布webservice,這種方式和直接放在pojo目錄中的POJO類不同。要想將MyService類發(fā)布成Web Service,需要一個services.xml文件,這個文件需要放在META-INF目錄中,該文件的內(nèi)容如下:
Xml代碼
1.
http://localhost:8080/axis2/services/myService?wsdl
除此之外,還有直接可以在其中制定webservice操作方法:可以這樣些service.xml文件
Java代碼
1. 10.11.service.HelloWorld 12.13. 14.15.
第二篇:個人對Java構(gòu)造方法調(diào)用的總結(jié)(精選)
個人對Java構(gòu)造方法調(diào)用的總結(jié)
1.構(gòu)造方法必須與定義它的類有完全相同的名字。構(gòu)造方法沒有返回類型,也沒有void。
2.類可以不聲明構(gòu)造方法,這時類中隱含聲明了一個方法體為空的無參構(gòu)造方法。但當(dāng)類有明確聲明構(gòu)造方法時,它就不會自動生成。
3.構(gòu)造方法的調(diào)用:子類首先要調(diào)用父類的構(gòu)造方法才能繼承父類的屬性和方法。如果子類的構(gòu)造方法中沒有顯式地調(diào)用父類的構(gòu)造方法,則系統(tǒng)默認(rèn)調(diào)用父類無參數(shù)的構(gòu)造方法。說說3種情況:
①父類和子類都沒有顯式定義構(gòu)造方法或者只定義了無參構(gòu)造方法,這種情況下沒有問題,Java 會順著繼承結(jié)構(gòu)往上一直找到 Object,然后從 Object 開始往下依次執(zhí)行構(gòu)造函數(shù)。以下兩個例子效果一樣,只是Example2有相關(guān)輸出: Example1 public class test1 { public static void main(String[] args){
A example =new A();} }
class A extends B{ } class B{ }
Example2:
public class test { public static void main(String[] args){
A example =new A();} }
class A extends B{ public A(){
System.out.println(“A's constructor is invoked.”);} } class B{ public B(){ System.out.println(“B's constructor is invoked.”);} } 輸出:B's constructor is invoked
A's constructor is invoked
②父類只定義有參構(gòu)造方法,那么無論子類如何定義,編譯都會報(bào)錯,因?yàn)楦割惾鄙倭四J(rèn)無參構(gòu)造方法,需要顯式定義。
public class test { public static void main(String[] args){
A example =new A(3);} }
class A extends B{ public A(int a){
System.out.println(“A's constructor is invoked.”+“a=”+a);} }
class B{ private int b=0;//public B(){ // System.out.println(“B's constructor is invoked.”);//}
public B(int b){
System.out.println(“B's constructor is invoked.”+“b=”+b);} } 把注釋符去掉就可以編譯,輸出:B's constructor is invoked.A's constructor is invoked.a=3
③在父類只有有參構(gòu)造方法而沒有無參構(gòu)造方法時,可以用super(參數(shù))來調(diào)用父類構(gòu)造方法,但super無參時需要父類的無參構(gòu)造方法。public class test { public static void main(String[] args){
A example =new A(3);} }
class A extends B{ public A(int a){
super(a);
System.out.println(“A's constructor is invoked.”+“a=”+a);} } class B{ private int b=0;
public B(int b){
System.out.println(“B's constructor is invoked”+“b=”+b);} } 輸出:B's constructor is invoked.b=3 A's constructor is invoked.a=3 此處指定用super(3)調(diào)用public B(int b),所以就有如下輸出: B's constructor is invoked.b=3 A's constructor is invoked.a=3
第三篇:用java調(diào)用oracle存儲過程總結(jié)
用java調(diào)用oracle存儲過程總結(jié)
分類: PL/SQL系列 2009-09-24 15:08 253人閱讀 評論(0)收藏 舉報(bào)
聲明:
以下的例子不一定正確,只是為了演示大概的流程。
一:無返回值的存儲過程 存儲過程為:
CREATE OR REPLACE PROCEDURE TESTA(PARA1 IN VARCHAR2,PARA2 IN VARCHAR2)AS BEGIN
INSERT INTO HYQ.B_ID(I_ID,I_NAME)VALUES(PARA1, PARA2);END TESTA;
然后呢,在java里調(diào)用時就用下面的代碼: package com.hyq.src;
import java.sql.*;import java.sql.ResultSet;
public class TestProcedureOne {
public TestProcedureOne(){
}
public static void main(String[] args){
String driver = “oracle.jdbc.driver.OracleDriver”;
String strUrl = “jdbc:oracle:thin:@127.0.0.1:1521: hyq ”;
Statement stmt = null;
ResultSet rs = null;
Connection conn = null;
CallableStatement cstmt = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(strUrl, “ hyq ”, “ hyq ”);
CallableStatement proc = null;
proc = conn.prepareCall(“{ call HYQ.TESTA(?,?)}”);
proc.setString(1, “100”);
proc.setString(2, “TestOne”);
proc.execute();
}
catch(SQLException ex2){
ex2.printStackTrace();
}
catch(Exception ex2){
ex2.printStackTrace();
}
finally{
try {
if(rs!= null){
rs.close();
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
}
}
catch(SQLException ex1){
}
}
} }
二:有返回值的存儲過程(非列表)
當(dāng)然了,這就先要求要建張表TESTTB,里面兩個字段(I_ID,I_NAME)。
存儲過程為: CREATE OR REPLACE PROCEDURE TESTB(PARA1 IN VARCHAR2,PARA2 OUT VARCHAR2)AS BEGIN
SELECT INTO PARA2 FROM TESTTB WHERE I_ID= PARA1;END TESTB;
在java里調(diào)用時就用下面的代碼: package com.hyq.src;
public class TestProcedureTWO {
public TestProcedureTWO(){
}
public static void main(String[] args){
String driver = “oracle.jdbc.driver.OracleDriver”;
String strUrl = “jdbc:oracle:thin:@127.0.0.1:1521:hyq”;
Statement stmt = null;
ResultSet rs = null;
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(strUrl, “ hyq ”, “ hyq ”);
CallableStatement proc = null;
proc = conn.prepareCall(“{ call HYQ.TESTB(?,?)}”);
proc.setString(1, “100”);
proc.registerOutParameter(2, Types.VARCHAR);
proc.execute();
String testPrint = proc.getString(2);
System.out.println(“=testPrint=is=”+testPrint);
}
catch(SQLException ex2){
ex2.printStackTrace();
}
catch(Exception ex2){
ex2.printStackTrace();
}
finally{
try {
if(rs!= null){
rs.close();
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
}
}
catch(SQLException ex1){
}
}
} }
}
注意,這里的proc.getString(2)中的數(shù)值2并非任意的,而是和存儲過程中的out列對應(yīng)的,如果out是在第一個位置,那就是proc.getString(1),如果是第三個位置,就是proc.getString(3),當(dāng)然也可以同時有多個返回值,那就是再多加幾個out參數(shù)了。
三:返回列表
由于oracle存儲過程沒有返回值,它的所有返回值都是通過out參數(shù)來替代的,列表同樣也不例外,但由于是集合,所以不能用一般的參數(shù),必須要用pagkage了.所以要分兩部分,1,建一個程序包。如下:
CREATE OR REPLACE PACKAGE TESTPACKAGE AS
TYPE Test_CURSOR IS REF CURSOR;end TESTPACKAGE;
2,建立存儲過程,存儲過程為:
CREATE OR REPLACE PROCEDURE TESTC(p_CURSOR out TESTPACKAGE.Test_CURSOR)IS BEGIN
OPEN p_CURSOR FOR SELECT * FROM HYQ.TESTTB;END TESTC;
可以看到,它是把游標(biāo)(可以理解為一個指針),作為一個out 參數(shù)來返回值的。在java里調(diào)用時就用下面的代碼: package com.hyq.src;import java.sql.*;
import java.io.OutputStream;import java.io.Writer;
import java.sql.PreparedStatement;import java.sql.ResultSet;import oracle.jdbc.driver.*;
public class TestProcedureTHREE {
public TestProcedureTHREE(){
}
public static void main(String[] args){
String driver = “oracle.jdbc.driver.OracleDriver”;
String strUrl = “jdbc:oracle:thin:@127.0.0.1:1521:hyq”;
Statement stmt = null;
ResultSet rs = null;
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(strUrl, “hyq”, “hyq”);
CallableStatement proc = null;
proc = conn.prepareCall(“{ call hyq.testc(?)}”);
proc.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);
proc.execute();
rs =(ResultSet)proc.getObject(1);
while(rs.next())
{
System.out.println(“
}
}
catch(SQLException ex2){
ex2.printStackTrace();
}
catch(Exception ex2){
ex2.printStackTrace();
}
finally{
try {
if(rs!= null){
rs.close();
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
}
}
catch(SQLException ex1){
}
}
} }
四。Hibernate調(diào)用存儲過程
Connection con = session.connect();
CallableStatement proc = null;
con = connectionPool.getConnection();
proc = con.prepareCall(“{ call set_death_age(?, ?)}”);proc.setString(1, XXX);
proc.setInt(2, XXx);...proc.execute();
session.close();
在Hibernate中調(diào)用存儲過程的示范代碼--
如果底層數(shù)據(jù)庫(如Oracle)支持存儲過程,也可以通過存儲過程來執(zhí)行批量更新。存儲過程直接在數(shù)據(jù)庫中運(yùn)行,速度更加快。在Oracle數(shù)據(jù)庫中可以定義一個名為batchUpdateStudent()的存儲過程,代碼如下:
create or replace procedure batchUpdateStudent(p_age in number)as begin update STUDENT set AGE=AGE+1 where AGE>p_age;end;以上存儲過程有一個參數(shù)p_age,代表學(xué)生的年齡,應(yīng)用程序可按照以下方式調(diào)用存儲過程: tx = session.beginTransaction();Connection con=session.connection();String procedure = “{call batchUpdateStudent(?)}”;CallableStatement cstmt = con.prepareCall(procedure);cstmt.setInt(1,0);//把年齡參數(shù)設(shè)為0 cstmt.executeUpdate();tx.commit();在以上代碼中,我用的是Hibernate的 Transaction接口來聲明事務(wù),而不是采用JDBC API來聲明事務(wù)。
存儲過程中有一個參數(shù)p_age,代表客戶的年齡,應(yīng)用程序可按照以下方式調(diào)用存儲過程:
代碼內(nèi)容
tx = session.beginTransaction();Connection con=session.connection();
String procedure = “{call batchUpdateCustomer(?)}”;
CallableStatement cstmt = con.prepareCall(procedure);
cstmt.setInt(1,0);//把年齡參數(shù)設(shè)為0
cstmt.executeUpdate();
tx.commit();
CREATE procedure selectAllUsers DYNAMIC RESULT SETS 1 BEGIN
DECLARE temp_cursor1 CURSOR WITH RETURN TO CLIENT FOR
SELECT * FROM test;
OPEN temp_cursor1;END;
映射文件中關(guān)于存儲過程內(nèi)容如下
............
{ ? = call selectAllUsers()}
{ ? = call selectAllUsers()} 也可以寫成{ call selectAllUsers()},如果有參數(shù)就寫成
{ ? = call selectAllUsers(?,?,?)}
代碼中對query設(shè)置相應(yīng)位置上的值就OK Java調(diào)用關(guān)鍵代碼如下
Session session = HibernateUtil.currentSession();
Query query = session.getNamedQuery(“selectAllUsers”);
List list = query.list();
System.out.println(list);
要求你的存儲過程必須能返回記錄集,否則要出錯
如果你的存儲過程是完成非查詢?nèi)蝿?wù)就應(yīng)該在配置文件用以下三個標(biāo)簽
setFirstResult(int)和setMaxResults(int)方法來分頁
第四篇:webService基礎(chǔ)總結(jié)
? WebService是一種跨編程語言和跨操作系統(tǒng)平臺的遠(yuǎn)程調(diào)用技術(shù)
? 所謂跨編程語言和跨操作平臺,就是說服務(wù)端程序采用java編寫,客戶端程序則可以采用其他編程語言編寫,反之亦然!跨操作系統(tǒng)平臺則是指服務(wù)端程序和客戶端程序可以在不同的操作系統(tǒng)上運(yùn)行。? 除了WebService外,常見的遠(yuǎn)程調(diào)用技術(shù)還有RMI(Remote method invoke)和CORBA,由于WebService的跨平臺和跨編程語言特點(diǎn),因此比其他兩種技術(shù)應(yīng)用更為廣泛,但性能略低。
? WebService使用SOAP協(xié)議實(shí)現(xiàn)跨編程語言和跨操作系統(tǒng)平臺
? WebService采用HTTP協(xié)議傳輸數(shù)據(jù),采用XML格式封裝數(shù)據(jù)(即XML中說明調(diào)用遠(yuǎn)程服務(wù)對象的哪個方法,傳遞的參數(shù)是什么,以及服務(wù)對象的返回結(jié)果是什么)。WebService通過HTTP協(xié)議發(fā)送請求和接收結(jié)果時,發(fā)送的請求內(nèi)容和結(jié)果內(nèi)容都采用XML格式封裝,并增加了一些特定的HTTP消息頭,以說明HTTP消息的內(nèi)容格式,這些特定的HTTP消息頭和XML內(nèi)容格式就是SOAP協(xié)議(simple object access protocol,簡單對象訪問協(xié)議)。
? SOAP協(xié)議 = HTTP協(xié)議 + XML數(shù)據(jù)格式
? HTTP協(xié)議和XML是被廣泛使用的通用技術(shù),各種編程語言對HTTP協(xié)議和XML這兩種技術(shù)都提供了很好的支持,WebService客戶端與服務(wù)器端使用什么編程語言都可以完成SOAP的功能,所以,WebService很容易實(shí)現(xiàn)跨編程語言,跨編程語言自然也就跨了操作系統(tǒng)
? WebService客戶端要調(diào)用一個WebService服務(wù),首先要有知道這個服務(wù)的地址在哪,以及這個服務(wù)里有什么方法可以調(diào)用,所以,WebService務(wù)器端首先要通過一個WSDL文件來說明自己家里有啥服務(wù)可以對外調(diào)用,服務(wù)是什么(服務(wù)中有哪些方法,方法接受的參數(shù)是什么,返回值是什么),服務(wù)的網(wǎng)絡(luò)地址用哪個url地址表示,服務(wù)通過什么方式來調(diào)用。? WSDL(webservice description language)是基于XML格式的,它是WebService客戶端和服務(wù)器端都能理解的標(biāo)準(zhǔn)格式,其中描述的信息可以分為what,where,how等部分!? WSDL文件保存在Web服務(wù)器上,通過一個url地址就可以訪問到它??蛻舳艘{(diào)用一個WebService服務(wù)之前,要知道該服務(wù)的WSDL文件的地址。WebService服務(wù)提供商可以通過兩種方式來暴露它的WSDL文件地址:
? 注冊到UDDI服務(wù)器,以便被人查找 ? 直接告訴給客戶端調(diào)用者,例如,在自己網(wǎng)站給出信息或郵件告訴。
第五篇:調(diào)用外部方法及工作流
調(diào)用外部方法及工作流
公開一個對象,來從執(zhí)行的工作流中傳給宿主應(yīng)用程序,或者從宿主應(yīng)用程序傳給工作流不就行了嗎?其實(shí),使用現(xiàn)有的串行化技術(shù),如.NET Remoting或者XML Web服務(wù),就可完成這些事。串行化,也叫序列化,它可把數(shù)據(jù)從原有的形式轉(zhuǎn)換成合適的形式,以在不同進(jìn)程甚至不同計(jì)算機(jī)之間進(jìn)行傳輸。
學(xué)習(xí)完本章,你將掌握:
1.創(chuàng)建并調(diào)用你的工作流外部的本地?cái)?shù)據(jù)服務(wù)
2.理解怎樣使用接口來為宿主進(jìn)程和你的工作流之間進(jìn)行通信。
3.使用設(shè)計(jì)的外部方法在你的工作流和宿主應(yīng)用程序之間傳輸數(shù)據(jù)。
4.在一個正執(zhí)行的工作流中調(diào)用其它工作流
在寫前面的章節(jié)時,我自己不斷地思考,“我不能再等了,我要弄清楚在哪里可把(工作流中的)真實(shí)數(shù)據(jù)返回到宿主應(yīng)用程序中!”為什么?做了這么多的活動和工作流的演示,但都沒有實(shí)際返回某些感興趣的東西給宿主應(yīng)用程序。我不知寫過多少我們感興趣的工作流的實(shí)例和演示,但至多只是僅僅處理過數(shù)據(jù)的初始化(就像第一章-WF簡介中你看過的郵政編碼的例子)。但事情變得更加有趣,坦率地說,當(dāng)我們啟動工作流,然后從外部源中尋找并處理數(shù)據(jù)、返回處理后的數(shù)據(jù)給我們的主應(yīng)用程序要更加接近現(xiàn)實(shí)。
為什么不這樣呢?公開一個對象,來從執(zhí)行的工作流中傳給宿主應(yīng)用程序,或者從宿主應(yīng)用程序傳給工作流不就行了嗎?其實(shí),使用現(xiàn)有的串行化技術(shù),如.NET Remoting或者XML Web服務(wù),就可完成這些事。串行化,也叫序列化,它可把數(shù)據(jù)從原有的形式轉(zhuǎn)換成合適的形式,以在不同進(jìn)程甚至不同計(jì)算機(jī)之間進(jìn)行傳輸。
為什么談到序列化呢?因?yàn)槟愕墓ぷ髁魇窃谀愕乃拗鬟M(jìn)程中的不同線程上執(zhí)行,不同線程之間傳送數(shù)據(jù),如不進(jìn)行適當(dāng)?shù)男蛄谢?,將會引發(fā)災(zāi)難,具體原因超出了本書的討論范圍。其實(shí),你的工作流能在一個持久化的狀態(tài)下發(fā)送它的數(shù)據(jù)。這并沒有在不同線程上,甚至它不在執(zhí)行中。
但我們想在我們的工作流和正控制該工作流的宿主進(jìn)程間傳送數(shù)據(jù)時,使用.NET Remoting或者XML Web服務(wù)這樣的技術(shù)為什么并沒有認(rèn)為是多余的呢?其實(shí)這絕對有必要!我們將創(chuàng)建local通信,本章將以此出發(fā)。我們將搭建必須的體系來滿足線程數(shù)據(jù)序列化,以進(jìn)行計(jì)算機(jī)之間或進(jìn)程之間的數(shù)據(jù)傳輸。
創(chuàng)建ExternalDataService服務(wù)
當(dāng)工作流和它的宿主進(jìn)行通信時,在它發(fā)送和接收數(shù)據(jù)的時候,工作流要使用隊(duì)列和消息。WF為我們做的越多,我們就可把重點(diǎn)更多的放到應(yīng)用中特定任務(wù)的解決上。
工作流內(nèi)部進(jìn)程通信
對于簡單的通信任務(wù),WF使用“abstraction layer”來在工作流和宿主之間進(jìn)行緩沖。抽象層像一個黑盒,你為它提供輸入,它會執(zhí)行一些神奇的任務(wù),然后信息流出到另一邊。但我們不用知道它是如何工作的。
在這種情形下,該黑盒就是一個知名的“l(fā)ocal communication”服務(wù)。和WF術(shù)語中的任何一種服務(wù)一樣,它也是另一種可插拔服務(wù)。區(qū)別是它不像WF中的那些已預(yù)先創(chuàng)建好的服務(wù),你需要寫出這個服務(wù)的一部分。為什么呢?因?yàn)槟阍谒拗鲬?yīng)用程序和你的工作流之間傳遞的數(shù)據(jù)有一定的特殊性。更進(jìn)一步說,你可創(chuàng)建各種各樣的數(shù)據(jù)傳輸方法,你可使用你設(shè)計(jì)的各種方法從宿主應(yīng)用程序發(fā)送數(shù)據(jù),然后在工作流中接收數(shù)據(jù)。
備注:這里有些事情你需要進(jìn)行關(guān)注,那就是對象或集合的共享問題。因?yàn)樗拗鲬?yīng)用程序和工作流運(yùn)行時在同一個應(yīng)用程序域執(zhí)行,因此引用類型的對象和集合就是通過引用而不是值進(jìn)行傳遞。這意味著宿主應(yīng)用程序和工作流實(shí)例在同一時間會訪問和使用同一個對象,多線程環(huán)境下這會產(chǎn)生bug,出現(xiàn)數(shù)據(jù)并發(fā)訪問錯誤。因此,對于可能要進(jìn)行并發(fā)訪問的對象或集合,你可考慮傳遞一個對象或集合的副本,或許這可通過實(shí)現(xiàn)ICloneable接口,或者考慮親自序列化該對象或集合并傳遞序列化后的版本。
你可寫這種local service,把它插進(jìn)工作流,然后打開連接,發(fā)送數(shù)據(jù)。這些數(shù)據(jù)可以是字符串,DataSet對象,甚至可以是你設(shè)計(jì)的任何可被序列化的自定義對象。通信可以是雙向的,盡管在本章我沒有演示它。(這里,我僅僅是把數(shù)據(jù)從工作流中傳回給宿主應(yīng)用程序。)從工作流的角度來說,我們使用工具生成活動的目的是發(fā)送和接收數(shù)據(jù)。從宿主應(yīng)用程序的角度來說,接收數(shù)據(jù)等同于一個事件,而發(fā)送數(shù)據(jù)就是在一個服務(wù)對象上的方法的簡單調(diào)用。
備注:我們在后面幾章看到更多的活動后還會重溫該雙向數(shù)據(jù)傳輸?shù)母拍?。工作流活動從宿主?yīng)用程序中接收數(shù)據(jù)基于一個HandleExternalEvent活動,我們將在第10章“Event活動”中看到。我們也需要更深入地了解這些概念間的相互關(guān)系,這在第17章“宿主通信”中將進(jìn)行介紹。對于當(dāng)前,我們只是在工作流實(shí)例完成它的任務(wù)后,簡單地返回復(fù)合數(shù)據(jù)給宿主。
我們需要做的還不僅僅是這一點(diǎn),我們最終需要添加ExternalDataService服務(wù)到我們的工作流運(yùn)行時中。ExternalDataService是一個可插拔的服務(wù),它方便了工作流實(shí)例和宿主應(yīng)用程序之間進(jìn)行序列化數(shù)據(jù)的傳輸。在緊接下來的一節(jié)我們將寫出的該服務(wù)的代碼將做很多事(包括序列化數(shù)據(jù)的傳輸)。讓我們來看看大體的開發(fā)過程。