【问题标题】:How to implement the Observer pattern with Java RMI?如何使用 Java RMI 实现观察者模式?
【发布时间】:2009-07-27 12:06:19
【问题描述】:

我有一个客户端在服务器上启动一个长时间运行的进程。每隔一段时间,我想向用户展示后台发生的事情。最简单的方法是轮询服务器,但我想知道是否没有办法为此实现观察者模式。不幸的是,我正在使用 RMI 与服务器通信,我担心我必须为此将我的客户端变成 RMI 服务器。

还有其他我想念的方法吗?

【问题讨论】:

标签: java rmi observer-pattern


【解决方案1】:
【解决方案2】:

RMI 通常可以支持双向通信。 (是的,RMI 是一个可以设置的 PITA,可以用来做任何其他事情。)

但是,通过 CGI 脚本 (!) 工作的 HTTP 传输不支持它。

【讨论】:

  • 当我在代码中使用 LocateRegistry.createRegistry()(而不是使用 Sun 提供的可执行文件)启动服务器时,仍然如此吗?
  • +1 表示“(是的,RMI 是一个可以设置的 PITA,可以用来做任何其他事情。)”请告诉我的学校。
【解决方案3】:

在这里整合所有答案,我在客户端和服务器之间实现了 2 路 RMI,服务器使用 Registry 公开其存根

  1. 客户端从 rmi 注册表获取服务器的存根
  2. 然后客户端将其作为 Observer 的存根放到服务器的 addObserver 方法中
  3. 服务器使用此存根通知客户端

下面的代码会给出更好的主意

import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import java.util.Observable;
import java.util.Observer;
import java.net.*;

import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;

interface ReceiveMessageInterface extends Remote
{
    /**
     * @param x
     * @throws RemoteException
     */
    void receiveMessage(String x) throws RemoteException;

    /**
     * @param observer
     * @throws RemoteException
     */
    void addObserver(Remote observer) throws RemoteException;
}

/**
 * 
 */
class RmiClient extends UnicastRemoteObject
{
    /**
     * @param args
     */
    static public void main(String args[])
    {
        ReceiveMessageInterface rmiServer;
        Registry registry;
        String serverAddress = args[0];
        String serverPort = args[1];
        String text = args[2];
        System.out.println("sending " + text + " to " + serverAddress + ":" + serverPort);
        try
        { // Get the server's stub
            registry = LocateRegistry.getRegistry(serverAddress, (new Integer(serverPort)).intValue());
            rmiServer = (ReceiveMessageInterface) (registry.lookup("rmiServer"));

            // RMI client will give a stub of itself to the server
            Remote aRemoteObj = (Remote) UnicastRemoteObject.exportObject(new RmiClient(), 0);
            rmiServer.addObserver(aRemoteObj);

            // call the remote method
            rmiServer.receiveMessage(text);
            // update method will be notified
        }
        catch (RemoteException e)
        {
            e.printStackTrace();
        }
        catch (NotBoundException e)
        {
            System.err.println(e);
        }
    }

    public void update(String a) throws RemoteException
    {
        // update should take some serializable object as param NOT Observable
        // and Object
        // Server callsbacks here
    }
}

/**
 * 
 */
class RmiServer extends Observable implements ReceiveMessageInterface
{
    String address;
    Registry registry;

    /**
     * {@inheritDoc}
     */
    public void receiveMessage(String x) throws RemoteException
    {
        System.out.println(x);
        setChanged();
        notifyObservers(x + "invoked me");
    }

    /**
     * {@inheritDoc}
     */
    public void addObserver(final Remote observer) throws RemoteException
    {
        // This is where you plug in client's stub
        super.addObserver(new Observer()
        {
            @Override
            public void update(Observable o,
                Object arg)
            {
                try
                {
                    ((RmiClient) observer).update((String) arg);
                }
                catch (RemoteException e)
                {

                }
            }
        });
    }

    /**
     * @throws RemoteException
     */
    public RmiServer() throws RemoteException
    {
        try
        {
            address = (InetAddress.getLocalHost()).toString();
        }
        catch (Exception e)
        {
            System.out.println("can't get inet address.");
        }
        int port = 3232;
        System.out.println("this address=" + address + ",port=" + port);
        try
        {
            registry = LocateRegistry.createRegistry(port);
            registry.rebind("rmiServer", this);
        }
        catch (RemoteException e)
        {
            System.out.println("remote exception" + e);
        }
    }

    /**
     * 
     * @param args
     */
    static public void main(String args[])
    {
        try
        {
            RmiServer server = new RmiServer();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

【讨论】:

  • 根据你的代码,当RmiServer类实现addObserver方法时,RmiClient类可以在服务器上使用。是客户端和服务端都定义的RmiClient类吗?
【解决方案4】:

我不认为你错过了什么。仅有的两种方法是定期调用服务器并检查状态(轮询)或注册服务器定期调用的回调(您的客户端必须公开一个方法)。 IMO,轮询是一种非常合理的处理方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-23
    • 1970-01-01
    • 2013-10-28
    • 2013-12-03
    相关资源
    最近更新 更多