使用servlet實現遠程調用

 讓我們先從這個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等等,都是你可以考慮的好東東。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章