讓我們先從這個servlet開始:
public class RemoteServlet extends HttpServlet {
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException ,java.io.IOException{
System.out.print("BaseDataServlet service received a remote request");
ObjectInputStream in = new ObjectInputStream(req.getInputStream());
resp.setContentType("application/octest-stream");
ByteArrayOutputStream byteout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteout);
Request request;
try {
request = (Request)in.readObject();//讀取遠程調用請求的封裝對象
//System.out.println(":/n"+request.toString());
RequestProcessor processor=new RequestProcessor();//請求解析對象
out.writeObject(processor.processorLocalhost(request));//執行請求並回寫結果
out.flush();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
byte buf[]= byteout.toByteArray();
resp.setContentLength(buf.length);
ServletOutputStream servletout = resp.getOutputStream();
servletout.write(buf);
servletout.close();
}
}
這個servle從輸入流讀取遠程調用的請求(Request對象):request = (Request)in.readObject();再由解析器RequestProcessor調用請求的對象,然後將結果回傳給請求客戶端。Request封裝了請求的信息:
/**
* 對遠程調用請求的封裝
* @author wuxinyang
*/
public class Request implements java.io.Serializable{
//目標地址,如果爲localhost則爲本地方法調用。
private String server;
//spring bean的配置名稱,如果配置了該值則通過spring配置裝載service。
private String serviceBeanName;
//服務的接口class名稱,必須帶包名
private String serviceInterface;
//要調用的方法名稱
private String methodName;
//返回類型,該值不是必須的。
private String returnType="void";
//傳入的參數列表
private java.util.List arguments=new java.util.ArrayList();
/**
* 構造方法
* @param server 目標地址
* @param serviceInterface spring bean的配置名稱
* @param methodName 方法名稱
*/
public Request(String server, String serviceInterface, String methodName) {
super();
this.server = server;
this.serviceInterface = serviceInterface;
this.methodName = methodName;
}
/**
* 添加調用參數
* @param arg 調用參數
*/
public void addArgument(Object arg){
arguments.add(arg);
}
public java.util.List getArguments() {
return arguments;
}
public void setArguments(java.util.List arguments) {
this.arguments = arguments;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getReturnType() {
return returnType;
}
public void setReturnType(String returnType) {
this.returnType = returnType;
}
public String getServer() {
return server;
}
public void setServer(String server) {
this.server = server;
}
public String getServiceInterface() {
return serviceInterface;
}
public void setServiceInterface(String serviceInterface) {
this.serviceInterface = serviceInterface;
}
public String getServiceBeanName() {
return serviceBeanName;
}
public void setServiceBeanName(String serviceBeanName) {
this.serviceBeanName = serviceBeanName;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return new ToStringBuilder(this).append("serviceInterface",
this.serviceInterface).append("serviceBeanName",
this.serviceBeanName).append("returnType", this.returnType)
.append("arguments", this.arguments).append("server",
this.server).append("methodName", this.methodName)
.toString();
}
}
RequestProcessor類有如下方法:
public Object processorLocalhost(Request request) {
String serviceInterface = request.getServiceInterface();//服務的接口class名稱(被調用者的接口)
try {
Object service;
if(request.getServiceBeanName()!=null){
//通過Spring初始化
service=com.westerasoft.common.SpringBeanFactory.getBean(request.getServiceBeanName());
}
else{
//初始化
service = Class.forName(serviceInterface).newInstance();
}
Method method = null;
BeanInfo beanInfo = Introspector.getBeanInfo(service.getClass());
MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();
for (int i = 0; i < methodDescriptors.length; i++) {
MethodDescriptor descriptor = methodDescriptors[i];
method = descriptor.getMethod();
if (method.getName().equalsIgnoreCase(request.getMethodName()))
break;
method = null;
}
if (method != null) {
//調用請求的方法
return method.invoke(service, request.getArguments().toArray());
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
客戶端類如下:
public class RequestProcessorTest {
public static void main(String[] args) {
String urlString = "http://localhost:8080/wcommons/servlet/BaseDataServlet";
//urlString="localhost";
//請求調用遠程接口com.westerasoft.common.dnet.RemoteService的方法gbToUtf8(String src)
Request request = new Request(urlString,
"com.westerasoft.common.dnet.RemoteService", "gbToUtf81");
request.addArgument("中國人民解放軍ABC");//添加調用參數即方法gbToUtf81的參數
Object answer = (Object) processor(request );
System.out.println(answer);
request = new Request(urlString,null,"findUsers");
//請求調用遠程接口userManager(Spring配置的bean name)的findUsers()方法
request.setServiceBeanName("userManager"); answer = (Object) processor(request );
System.out.println(answer);
}
private Object processor(Request request) {
try {
URL url = new URL(request.getServer());
java.net.URLConnection con = url.openConnection();
con.setUseCaches(true);
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestProperty("Content-type", "application/octest-stream");
con.setRequestProperty("Content-length", "" + -1);
ObjectOutputStream dataout = new ObjectOutputStream(con
.getOutputStream());
dataout.writeObject(request);
dataout.flush();
dataout.close();
ObjectInputStream in = new ObjectInputStream(con.getInputStream());
Object obj = in.readObject();
in.close();
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
是不是極其簡單(^_^),可以實現遠程接口調用。記住你是通過servlet服務提供的,所以你也可以很容易的控制只對經過授權的用戶能夠遠程調用。實際應用中你也許需要更完善和強大的遠程調用框架,比如支持hibernate的延遲加載特性,和異構系統等等,那麼有很多好的解決方案供你選擇,已知的EJB,Spring,Webservice等等,都是你可以考慮的好東東。