Ad. 1: Обратите внимание, что удаленный клиент ничего не знает о классе ComputeEngine
, только об интерфейсе Compute
. Кроме того, реализация сервера может полностью измениться, но если интерфейс не изменится, клиент не должен заметить. Если вы хотите передать некоторый контекст задаче, исходящей от удаленного клиента, сделайте это на уровне интерфейса:
public class ComputeEngine implements Compute {
private GlobalContext globalContext = //...
public <T> T executeTask(Task<T> t) {
return t.execute(globalContext);
}
Таким образом, каждая задача имеет доступ к globalContext
и точно знает, чего ожидать от globalContext
(каковы возможности сервера, контекст ). GlobalContext
будет JavaBean или, скорее, какой-нибудь интерфейс службы.
На стороне клиента это может выглядеть так
Compute compute = //obtain RMI client stub somehow
compute.executeTask(new Task<String>() {
public String execute(GlobalContext globalContext) {
//Note that this code is executed on the server and
//getFoo() is implemented on the server side. We only know its interface
globalContext.getFoo();
//...
}
}
Ad. 2: Он будет работать с несколькими клиентами, вызывающими службу одновременно. Однако вам необходимо реализовать сервер в поточно-ориентированном режиме. Пример из учебника, который вы упомянули в поточно-ориентированном виде, но мой код, использующий GlobalContext
, может и не быть. Обратите внимание, что несколько клиентов будут использовать один и тот же экземпляр globalContext
одновременно, что может, но не должно вызывать некоторые проблемы. Это, наверное, самая интересная часть.
И, наконец, помните, что получение неизвестного Task
с удаленного клиента и запуск его на сервере очень впечатляет, но не совсем безопасно.