走自己的路

路漫漫其修远兮,吾将上下而求索

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  50 随笔 :: 4 文章 :: 118 评论 :: 0 Trackbacks
 

1.本来trigger receiver流程的模块和接收者类是放在一个APP Server上的,但由于性能的考虑,这种schedule模块的调度和管理可能会影响业务逻辑的执行,占用业务逻辑执行的系统资源,所以将它放到单独的JVM上运行,作为一个Standalonejava application。这样schedule模块就不能直接通过内存调用接收者流程,接收者必须开放远程rpc服务,让trigger通过远程调用的方法主动调用消息接收者去接受消息。

原来的系统通过MessageReceiverFactory获得一个MessageReceiver 然后主动接收消息。



 

 

MessageReceiver:

public interface MessageReceiver {

      void invokeProcessFlow(String processId) throws ServerReceiverException;

}

 

ServerMessageReceiver:

 

public class ServerMessageReceiver implements MessageReceiver {  

      ServerMessageReceiver() {

 

      }

      public void invokeProcessFlow(String processId) throws ServerReceiverException {

        //receive message

}

 

 

 

 

MessageReceiverFactory:

 

public class MessageReceiverFactory {

      private static MessageReceiver messageReceiver;

 

      private static void init() throws ServerReceiverException {

            messageReceiver = new ServerMessageReceiver();

      }

 

 

      public synchronized static MessageReceiver getMessageReceiver() throws ServerReceiverException {

            if(messageReceiver == null) {

                  init();

            }

            return messageReceiver;

      }

     

}

 

2.增加RMI服务后:





 

客户端:

·         客户端通过MessageReceiverFactory获得MessageReceiver的远程版本:RemoteMessageReceiver

·         客户端使用远程版本的MessageReceiver  look upRemotableMessageReceiverRMI Stub进行远程的RPC调用,通知服务器端接收消息。

 

public class RemoteMessageReceiver implements MessageReceiver {

      private RemotableMessageReceiver messageReceiver;

      private String rmiHost;

      private int rmiPort;

      private String serviceName;

 

    public RemoteMessageReceiver(String host, int port, String serviceName) throws ServerReceiverException {

      try{

            this.rmiHost = host;

            this.rmiPort = port;

            this.serviceName = serviceName;

            Registry registry = LocateRegistry.getRegistry(rmiHost, rmiPort);

            messageReceiver = (RemotableMessageReceiver) registry.lookup(this.serviceName);

      }catch(Exception ex) {

            throw new ServerReceiverException("look up remote message receiver failed!", this, ex);

      }

     

      }

 

      public void invokeProcessFlow(String processId) throws ServerReceiverException {

            try {

                  this.messageReceiver.invokeProcessFlow(processId);

            } catch (RemoteException e) {

                  throw new ServerReceiverException(e.getMessage(), this, e);

            }

      }

}

 

这里用了适配器模式,对RemotableMessageReceiver进行适配,从而满足MessageReceiver接口的标准,方便MessageReceiverFactory的统一生产,并且使客户端使用的RemoteMessageReceiver和具体使用的通信方法解耦,将来如果不使用RMI, 只需要替换RemotableMessageReceiver就可以了。不会影响客户端的代码。

 

 

服务器端:

  • 服务器端设置开关,可以开启和关闭远程服务。
  • 如果开启远程服务,就需要注册服务,注册的服务对象是提供给客户端用的远程对象,服务端本身使用的MessageReceiver不需要实现RemotableMessageReceiver接口和原来一样实现MessageReceiver接口,从而原有的应用并没有太大影响。
  • 服务器端通过MessageReceiverFactory获得MessageReceiver也可以主动接受消息,如果需要提供远程服务,就必须注册远程服务。

 

这样,服务器端首先增加了RemotableMessageReceiver接口,所有远程对象实现该接口,RMIMessageReceiver提供RMI服务的远程对象,供客户端远程调用。RMIMessageReceiver必须满足RemotableMessageReceiver接口的契约,所以也使用了适配器模式。增加了RMIMessageReceiver后,服务器端使用的MessageReceiver就和RMIMessageReceiver耦合在一起了,为了解耦,我又新增了一个StdMessageReceiver类,作为服务器端本地的MessageReceiver,供服务器端本地调用,StdMessageReceiver用了装饰器模式,对已有的MessageReceiver进行修饰,支持服务器端本地调用,如果以后本地调用加了新的功能就不会影响RMIMessageReceiver的功能了,比如凡是本地调用都需要在服务器端记log,这样就只需要在StdMessageReceiver添加打log的功能,而不会影响RMIMessageReceiver

 

MessageReceiverFactory简单工厂用于生产MessageReceiver对象,可能是客户端的RemoteMessageReceiver也可能是服务器端的StdMessageReceiver

 

为了在deploy时候就启动RMI服务,我们可以在servletinit方法中初始化并注册RMI服务,在deetroy方法中相应的取消RMI服务。

 

RemotableMessageReceiver: 远程服务对象接口

public interface RemotableMessageReceiver extends Remote {

      void invokeProcessFlow(String processId) throws ServerReceiverException,

                  RemoteException;

}

 

 

 

RMIMessageReceiver:提供RMI服务的远程对象

public class RMIMessageReceiver implements RemotableMessageReceiver {

      private MessageReceiver messageReceiver;

 

      RMIMessageReceiver(MessageReceiver messageReceiver) throws RemoteException {

            this.messageReceiver = messageReceiver;

            SystemInfo sysInfo = ContextFactory.getSystemConfigContext().getSystemInfo();

            System.out.println("beign to bind at rmiport: " + sysInfo.getRmiport());

            RMIUtils.bind(sysInfo.getRmiport(), sysInfo

                        .getReceiverRmiBindName(), this);

      }

 

      public void invokeProcessFlow(String processId)

                  throws ServerReceiverException, RemoteException {

            this.messageReceiver.invokeProcessFlow(processId);

      }

 

}

 

SystemInfo存储的是一些配置信息,比如是不是服务器端,是不是需要开启远程服务,如果开启的话相应的hostportrmi远程对象绑定的服务名

 

StdMessageReceiver:服务器端使用的MessageReceiver

public class StdMessageReceiver implements MessageReceiver {

      private MessageReceiver messageReceiver;

 

      public StdMessageReceiver(MessageReceiver messageReceiver) {

            this.messageReceiver = messageReceiver;

      }

 

      public void invokeProcessFlow(String processId) throws ServerReceiverException {

            //do some log

            this.messageReceiver.invokeProcessFlow(processId);

      }

}

 

MessageReceiverFactory: 生产MessageReceiver的简单工厂:

public class MessageReceiverFactory {

      private static MessageReceiver messageReceiver;

      private static RemotableMessageReceiver remotableMessageReceiver;

 

      private static void init() throws ServerReceiverException {

            SystemInfo sysInfo = ContextFactory.getSystemConfigContext()

                        .getSystemInfo();

            if (sysInfo.isServer()) {

                  MessageReceiver mifMessageReceiver = new ServerMessageReceiver();

                  if (sysInfo.isRemoteable()) {

                        try {

                              remotableMessageReceiver = new RMIMessageReceiver(mifMessageReceiver);

                        } catch (RemoteException e) {

                              throw new ServerReceiverException(

                                          "bind Message Receiver to port: "

                                                      + sysInfo.getRmiport()

                                                      + " with service name: "

                                                      + sysInfo.getReceiverRmiBindName(), e);

                        }

                  }

                 

                  messageReceiver = new StdMessageReceiver(mifMessageReceiver);

 

            } else {

                  String rmiHost = sysInfo.getRmiHost();

                  int rmiPort = sysInfo.getRmiport();

                  String serviceName = sysInfo.getReceiverRmiBindName();

                  messageReceiver = createRemoteMesageReceiver(rmiHost, rmiPort,

                              serviceName);

            }

      }

 

      public static MessageReceiver createRemoteMesageReceiver(String rmiHost,

                  int rmiPort, String serviceName) throws ServerReceiverException {

            return new RemoteMessageReceiver(rmiHost, rmiPort, serviceName);

      }

 

      public synchronized static MessageReceiver getMessageReceiver() throws ServerReceiverException {

            if(messageReceiver == null) {

                  init();

            }

            return messageReceiver;

      }

     

      public static RemotableMessageReceiver getRemoteableMesageReceiver(){

            return remotableMessageReceiver;

      }

     

      public synchronized static void initMessageReceiver() throws ServerReceiverException {

            init();

      }

}

  

StartUpServlet:启动时(deploy)时parse config并且初始化MessageReceiver

publicclass StartupServlet extends HttpServlet {

      public void init(ServletConfig config) throws ServletException {

            try {

                  //parse configuration

                 

                  //init rmi service

                  MessageReceiverFactory.initMessageReceiver();

     

            } catch (Exception ex) {

                  ex.printStackTrace();

                  thrownew ServletException(ex.getMessage(), ex);

            }

      }

      publicvoid destroy() {

            try {

                 

                  RemotableMessageReceiver remotableMessageReceiver = MessageReceiverFactory

                              .getRemoteableMesageReceiver();

                  if (remotableMessageReceiver != null) {

                        SystemInfo sysInfo = ContextFactory.getSystemConfigContext()

                                    .getSystemInfo();

                        RMIUtils.unBind(sysInfo.getRmiport(), sysInfo

                                    .getReceiverRmiBindName(),

                                    remotableMessageReceiver);

                  }

            } catch (Exception e) {

                  e.printStackTrace();

            }

      }

}

 

RMIUtils: 工具类提供rmi注册和撤销服务的功能:

public class RMIUtils {

      public static void  bind(int rmiPort, String serviceName, Remote remoteObject)

                  throws RemoteException {

            SystemInfo sysInfo = ContextFactory.getSystemConfigContext()

                        .getSystemInfo();

            Remote exportable = (Remote) UnicastRemoteObject

                        .exportObject(remoteObject);

 

            Registry registry = null;

 

            try {

                  registry = LocateRegistry.getRegistry(sysInfo.getRmiport());

                  registry.list();

            } catch (Exception e) {

                  registry = LocateRegistry.createRegistry(sysInfo.getRmiport());

            }

            registry.list();

            System.out.println("bind the service: " + serviceName);

            String bindName = serviceName;

 

            registry.rebind(bindName, exportable);

 

      }

 

     

      public static void unBind(int rmiPort, String serviceName, Remote remoteObject) throws RemoteException {         

            SystemInfo sysInfo = ContextFactory.getSystemConfigContext()

            .getSystemInfo();

 

            Registry registry = LocateRegistry.getRegistry(sysInfo.getRmiport());

 

            String bindName = serviceName;

 

            try {

                  registry.unbind(bindName);

                  UnicastRemoteObject.unexportObject(remoteObject, true);

            } catch (java.rmi.NotBoundException nbe) {

            }

      }

}





评论

# re: 让已有的系统开放RMI服务[未登录] 2008-10-27 13:27 attend
顶,好文章.  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: