為什么要這樣做
在目前所做的一個項目中,我們使用了兩臺獨(dú)立的數(shù)據(jù)庫服務(wù)器,出于安全方面的考慮,我們同時使用兩臺Web服務(wù)器分別操作這兩個數(shù)據(jù)庫。這就形成了這樣的一個結(jié)構(gòu)圖:
由于數(shù)據(jù)庫服務(wù)器A和服務(wù)庫服務(wù)器B之間存在著數(shù)據(jù)的交換,而WEB服務(wù)器A并不能直接訪問數(shù)據(jù)庫服務(wù)器B,同理WEB服務(wù)器B也不能直接訪問數(shù)據(jù)庫服務(wù)器A。這樣的交換只能是通過兩臺Web主機(jī)來進(jìn)行。而在絕大多數(shù)時候,我們涉及的是較大規(guī)模的數(shù)據(jù)交換,使用帶參數(shù)的格式顯然不能滿足我們的要求,這就涉及了不同Web主機(jī)上的Servlet之間數(shù)據(jù)對象的相互傳輸?shù)膯栴}。
使用通常的Application域或是Session域的javabean看上去不能滿足我們的要求,雖然我們相信會有很多更為完美的方案可以解決這個問題,但是我們今天想看看如何直接通過HTTP連接來完成這樣的傳輸。
首先對于我們的每一個獨(dú)立的應(yīng)用來說,兩臺WEB服務(wù)器都會存在一個主次的關(guān)系,情況也許是這樣的:訪問者訪問WEB服務(wù)器A上的一個servlet A,而這個servlet A產(chǎn)生一個數(shù)據(jù)對象傳輸?shù)絎EB服務(wù)器B上的另一個servlet B,servlet B接收到這個數(shù)據(jù)對象后對其進(jìn)行相應(yīng)的處理,然后它可能還會生成另一個數(shù)據(jù)對象傳輸?shù)絪ervlet A中。這樣的過程看上去有點(diǎn)象一個遠(yuǎn)程函數(shù)調(diào)用的概念。限于篇幅的限制,我們這里討論一種較為簡單的情況,test將passobject傳輸?shù)絫est2,test2對passobject進(jìn)行處理后將其傳回到test。
簡單示例的源碼
passobject.java
首先,我們需要在兩臺WEB主機(jī)上分別建立對passobject的定義,在兩臺主機(jī)上的定義應(yīng)該是完全一樣,這樣的類定義和我們通常使用并沒有什么不同。只是這樣的類必須實現(xiàn)序列化,也就是要實現(xiàn)Serializable:
package test;
import java.io.*;

public class PassObject implements Serializable
{
String PassValue1;
String PassValue2;
public void setNewPassObject()

{PassValue1="yzysynew";
PassValue2="new";
}
public void setOldPassObject()

{PassValue1="yzysyold";
}
}
test.java
在其中的一臺web主機(jī)上建立。除去加注釋的那幾行,這完全是一個通常意義上的用于顯示的servlet,不過那幾行的內(nèi)容看上去也許會有點(diǎn)讓你眼花繚亂。這幾行將數(shù)據(jù)對象傳輸?shù)搅肆硪慌_主機(jī)的test2中,并接收經(jīng)過test2處理的數(shù)據(jù)對象。對于這里所涉及的一些不太常用的API,我們將會在最后一并說明。
package test;
import java.sql.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.io.*;
import java.net.*;

public class Test extends HttpServlet
{
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException

{PassObject passobject = new PassObject();
passobject.setNewPassObject();
PrintWriter out = response.getWriter();
out.println(passobject.PassValue1);
out.println(passobject.PassValue2);
//創(chuàng)建一個新的URL實例url
URL url = new URL("http://141.56.16.8/examples/servlet/test.Test2");
//根據(jù)url建立連接
URLConnection con = url.openConnection();
//設(shè)置該連接可寫
con.setDoOutput(true);
//禁用cache
con.setUseCaches(false);
//取出輸出流
OutputStream outs=con.getOutputStream();
//將該輸出流轉(zhuǎn)換為對象輸出流
ObjectOutputStream objout = new ObjectOutputStream(outs);
//將要傳輸?shù)膶ο髮懭朐搶ο筝敵隽髦?/span>
objout.writeObject(passobject);
//取得返回的輸入流
InputStream in = con.getInputStream();
//將該輸入流定義為對象輸入流
ObjectInputStream objStream;
objStream = new ObjectInputStream(in);
//按指定類的格式讀取輸入流的內(nèi)容

try
{
passobject=(PassObject)objStream.readObject();
out.println(passobject.PassValue1);
out.println(passobject.PassValue2);
}
catch (java.lang.ClassNotFoundException ysy )

{
out.println("fail");
}
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException

{
doGet(request, response);
}
}
test2.java
在其中的另一臺web主機(jī)上建立,用來接收test發(fā)送的數(shù)據(jù)對象,并對其進(jìn)行處理后返回到test。
package test;
import java.sql.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.io.*;
import java.net.*;

public class Test2 extends HttpServlet
{
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException

{//封裝用于返回的對象輸出流
ObjectOutputStream out = new ObjectOutputStream(response.getOutputStream());
//封裝用于接收的對象輸入流
ObjectInputStream in = new ObjectInputStream(request.getInputStream());
PassObject passobject=new PassObject();
//按指定類的格式讀取對象輸入流中的內(nèi)容

try
{
passobject=(PassObject)in.readObject();
}
catch (java.lang.ClassNotFoundException ysy )

{
}
//對接受到的數(shù)據(jù)對象進(jìn)行處理
passobject.setOldPassObject();
//將處理后的數(shù)據(jù)對象返回到對象輸出流中
out.writeObject(passobject);
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException

{
doGet(request, response);
}
}
程序中涉及的部分API的說明
java.net.URL
URL類表示了一個統(tǒng)一資源路徑。這樣的資源可能是一個文件或目錄,也可能是更為復(fù)雜的諸如數(shù)據(jù)庫的查詢或是搜索引擎。
在我們的程序中使用了URL的一種構(gòu)造函數(shù):
URL(String spec)
直接使用字符串作為構(gòu)造函數(shù)的參數(shù),這實際上是URL的眾多構(gòu)造函數(shù)中最為簡單的一種。
此外,我們還用到了URL的openConnection()方法:
public URLConnection openConnection()
throws IOException
該方法返回了一個URLConnection對象。每次調(diào)用該方法時會開啟一個到指定URL的新的連接。
這里需要注意的是,調(diào)用該方法的結(jié)果是建立了一個連接,這與通常的頁面跳轉(zhuǎn)完全是兩回事。在更多的情況下,這里僅僅是建立了一個連接的通路,而并沒有實現(xiàn)任何其它的操作。
java.net.URLConnection
這是一個抽象類,是所有反映application和一個URL之前的通信的類的超類。這個類的實例可以用來對一個URL表示的資源進(jìn)行讀寫。
在我們的程序中我們使用了這個類的如下方法:
getInputStream
public InputStream getInputStream()
throws IOException
返回從這個連接讀取的一個輸入流
getOutputStream
public OutputStream getOutputStream()
throws IOException
返回一個用于寫入這個連接的輸出流
setDoOutput
public void setDoOutput(boolean dooutput)
設(shè)置該連接是否可以寫入
setUseCaches
public void setUseCaches(boolean usecaches)
設(shè)置該連接是否使用cache
java.io.OutputStream
這是一個抽象類,是所有反映一個二進(jìn)制輸出流的類的超類。一個這樣的輸出流可以對二進(jìn)制數(shù)據(jù)進(jìn)行輸出或發(fā)送。
java.io.ObjectOutputStream
該類用來向一個OutputStream寫入java的對象。這個對象可以使用ObjectInputStream進(jìn)行讀取或再造。
只有實現(xiàn)java.io.Serializable接口的對象可以寫入該數(shù)據(jù)流中。
在我們的程序中還使用了該類的writeObject()方法:
public final void writeObject(Object obj)
throws IOException
將指定的對象寫入ObjectOutputStream。
java.io.InputStream
這是一個抽象類,是所有反映一個二進(jìn)制輸入流的類的超類。
java.io.ObjectInputStream
一個ObjectInputStream對一個使用ObjectOutputStream寫入的對象進(jìn)行解析。
在我們的程序中使用了該類的readObject()方法:
public final Object readObject()
throws OptionalDataException,
ClassNotFoundException,
IOException
從一個ObjectInputStream中讀取一個對象。
程序執(zhí)行的結(jié)果
如果一切正常,訪問test.Test你應(yīng)該可以看到這樣的結(jié)果:
yzysynew
new
yzysyold
new
其中yzysynew,new是對象原來的內(nèi)容,而yzysyold,new所反映的那個對象已經(jīng)是傳送到test2后經(jīng)test2處理過的了。