Главная » Spring » Внедрение службы RMI Spring

0

Для поиска службы в реестре RMI клиенты традиционно должны использовать класс Naming из RMI API. Например, для получения ссылки на RMI-службу приложения Spitter можно использовать следующий фрагмент:

try  {

String    serviceUrl    =    "rmi:/spitter/SpitterService"; SpitterService   spitterService   =

(SpitterService)   Naming.lookup(serviceUrl);

catch (RemoteException e) { … } catch (NotBoundException e) { … }

catch (MalformedURLException e) { … }

Несмотря на то что этот фрагмент позволяет получить ссылку на RMI-службу spitter, тем не менее в нем присутствуют две проб- лемы:

# в результате типичного поиска службы RMI может быть воз-

буждено одно из трех контролируемых исключений (Remote- Exception, NotBoundException и MalformedURLException), которые не- обходимо перехватить и возбудить заново;

# ответственность за извлечение службы spitter несет сам про-

граммный код, пользующийся ею, – это шаблонный код, никак не связанный с функциональностью клиента.

Исключения, возбуждаемые в процессе поиска службы RMI, яв- ляются своего рода сигналами о фатальной ошибке в приложении. Исключение MalformedURLException, например, указывает на недопусти- мый адрес службы. Чтобы восстановить работу приложения после этого исключения, необходимо как минимум перенастроить прило- жение и, возможно, скомпилировать его заново. Никакие ухищрения в блоке try/catch не способны исправить эту ошибку, тогда зачем вы- нуждать программный код перехватывать и обрабатывать его?

Что еще хуже, такой программный код действует в полной проти- воположности принципам внедрения зависимостей. Поскольку кли- ент целиком отвечает за поиск службы Spitter и эта служба является RMI-службой, нет никакой возможности подставить иную реализа- цию службы SpitterService. В  идеале  объект  SpitterService  должен был бы внедряться в требуемый компонент, вместо того чтобы за- ставлять его искать службу самостоятельно. Благодаря поддержке DI любой клиент службы SpitterService может вообще не иметь ни- какого понятия, откуда взялась эта служба.

Компонент RmiProxyFactoryBean в Spring – это фабричный ком- понент, создающий прокси-объект, представляющий службу RMI. С помощью RmiProxyFactoryBean легко можно реализовать получение ссылки на RMI-службу SpitterService, как показано в следующем фрагменте конфигурационного файла клиентского приложения:

<bean  id="spitterService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean" p:serviceUrl="rmi://localhost/SpitterService" p:serviceInterface="com.habuma.spitter.service.SpitterService"      />

Адрес URL службы определяется свойством serviceUrl компонента RmiProxyFactoryBean. В данном случае служба имеет имя SpitterService и выполняется на локальном компьютере. Интерфейс, предостав- ляемый службой, определяется свойством serviceInterface. Порядок взаимодействий между клиентом и прокси-объектом показан на рис. 11.5.

Рис. 11.5. RmiProxyFactoryBean создает прокси-объект, реализующий взаимодействия с с удаленными службами RMI от имени клиента. Клиент взаимодействует с прокси-объектом, используя интерфейс службы, как если бы удаленная служба была простым, локальным Java-объектом POJO

Теперь, после объявления службы RMI в виде компонента, управ- ляемого фреймворком Spring, можно внедрить ее в виде зависимо- сти в другой компонент как обычный локальный компонент. На- пример, предположим, что служба Spitter будет использоваться для извлечения списка сообщений (объектов Spittle), принадлежащих указанному пользователю. Внедрить прокси-объект в клиента мож- но с помощью аннотации @Autowired:

@Autowired

SpitterService spitterService;

А затем вызывать методы службы, как если бы она была локаль- ным компонентом:

public List<Spittle> getSpittles(String userName)  {   Spitter  spitter  =  spitterService.getSpitter(userName); return        spitterService.getSpittlesForSpitter(spitter);

Вся прелесть такого способа обращения к службе RMI состоит в том, что клиенту не требуется даже знать, что он взаимодейству- ет со службой RMI. Он получает объект SpitterService  посредством внедрения, без необходимости беспокоиться о том, откуда он по- явился.

Кроме того, прокси-объект автоматически будет перехватывать все исключения RemoteExceptions и повторно возбуждать их как не- контролируемые исключения, которые можно попросту игнориро- вать. Такой подход существенно упрощает замену одной реализации службы другой, которая, в свою очередь, также может быть удален- ной службой или фиктивным объектом, используемым для тестиро- вания клиентского программного кода.

Несмотря на то что клиент не знает, что служба SpitterService, с которой он взаимодействует, является удаленной службой, вам необходимо со всем вниманием подойти к проектированию интер- фейса службы. Обратите внимание, что клиент производит два об- ращения к службе: один, чтобы получить объект Spitter по имени пользователя, и другой, чтобы получить список объектов Spittle с сообщениями. Скорость выполнения этих двух вызовов зависит от задержек, связанных с передачей данных по сети, и оказывает влияние на общую производительность клиента. Зная, как будет ис- пользоваться служба, имеет смысл перепроектировать интерфейс и объединить эти два вызова в один. Но пока оставим все как есть.

Модель RMI – отличный способ взаимодействия с удаленными службами, но имеет некоторые ограничения. Во-первых, модель RMI значительно сложнее в реализации при наличии сетевых экра- нов (брандмауэров). Это обусловлено тем, что для взаимодействий RMI использует произвольные порты – что обычно не допускается брандмауэрами. В локальных сетях это не является большой проб- лемой. Но если предполагается, что взаимодействия будут выпол- няться через Интернет, вы определенно столкнетесь с проблемами. Даже при том, что RMI поддерживает туннелирование через HTTP (что обычно позволяет преодолевать брандмауэры), настройка тун- нелирования в RMI – весьма непростая задача.

Еще одна проблема заключается в том, что модель RMI основана на языке Java. То есть и клиент, и служба должны быть реализованы на языке Java. А поскольку в RMI используется механизм сериа- лизации языка Java, версии типов объектов, передаваемых по сети, должны совпадать в обеих взаимодействующих сторонах. Возможно, это и не является проблемой для вашего приложения, но вы долж-

ны помнить об этой особенности, выбирая модель RMI удаленных взаимодействий.

В рамках проекта Caucho Technology (где работают те же люди, создавшие сервер приложений Resin) было разработано решение удаленных взаимодействий, свободное от ограничений, свойствен- ных RMI. В действительности было создано два решения: Hessian и Burlap. Посмотрим, как организовать удаленные взаимодействия с применением Hessian и Burlap в Spring.

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии