Использование Spring Remoting

Q: В Spring есть возможность работать с Remoting. Собственно нужен самый простой пример этого: запуск сервиса и обращение к нему клиента.

В двух словах об удаленном доступе

Действительно, Spring framework предоставляет богатые возможности как по созданию удаленных служб так и по доступу к ним. На данный момент в распоряжении разработчиков поддержка нескольких моделей удаленного доступа с использованием таких технологий как

  • Удаленный вызов процедур (RMI)
  • Caucho’s Hessian and Burlap
  • Собственная реализация удаленного доступа через HTTP протокол (HTTP invoker)
  • Enterprise JavaBeans (EJB)
  • Ну и конечно Web службы (JAX-RPC)

Я не буду углубляться в концепцию и детали реализации каждой модели в Spring framework, а всего лишь обозначу основные моменты и приведу небольшой пример по организации удаленного доступа к некой службе с помощью RMI. Более детально обо всем о том, о чем я собираюсь умолчать, можно прочитать в замечательной книге “Spring In Action
Итак, независимо от выбранной модели, службы можно конфигурировать как Spring-managed бины. Делается это при помощи proxy factory bean-а, который позволяет передавать удаленные службы в качестве значения свойств других бинов так, как будто это обыкновенные локальные объекты. На рисунке показано как это работает.

diagramm.png

Клиент вызывает методы у прокси так, как будто прокси реализует функциональность службы. Прокси же в свою очередь взаимодействует с удаленной службой по требованию клиента. Он управляет деталями соединения со службой и выполняет удаленные вызовы к службе.
На серверной стороне Spring позволяет представить функциональность любого Spring-managed бина в виде удаленной службы используя любую из перечисленных выше моделей. На рисунки ниже показано как экспортер представляет методы бина в виде удаленных служб.

sdiagramm.png

Пример экспорта RMI службы

Пришло время показать небольшой пример работы с удаленными службами при помощи Spring. Для начала необходимо определить интерфейс, который будет реализовывать служба, и через который клиент будет обращаться к ней.


package remoting;
public interface HelloWorldService {
  String sayHello();
}

Теперь создадим реализацию службы


package remoting.server;
import remoting.HelloWorldService;
public class HelloWorldServiceImpl implements HelloWorldService {
  public String sayHello() {
    return "HelloWorld";
  }
}

Осталось только описать нашу службу в файле конфигурации Spring и экспортировать ее как RMI службу. Однако вместо стандартных процедур генерации стаба и скелетона с использованием rmic и добавления службы вручную в RMI registry, можно воспользоваться классом RmiServiceExporter.
Создаем файл /remoting/server/applicationContext.xml со следующим содержимым


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!--
  -	Объявляем службу как бин. Обратите внимание что здесь ничего не сказано о том,
  -	что это удаленная служба. Если необходимо, то эту реализацию можно использовать в
  -	обычном виде, передав ссылку на нее в необходимые бины.
  -->
  <bean id="helloWorldService" class="remoting.server.HelloWorldServiceImpl"/>
<!--
  -	RmiServiceExporter экспортирует любой Spring-managed бин в виде RMI службы. Делает
  -	он это декорируя бин классом-адаптером. Адаптер затем регистрируется в RMI реестре
  -	и перправляет удаленные вызовы к службе методам декорируемого бина, в данном случае
  -	объекту класса HelloWorldServiceImpl
  -->
  <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="HelloWorldService"/>
<property name="service"><ref local="helloWorldService"/></property>
<property name="serviceInterface" value="remoting.HelloWorldService"/>
<property name="registryPort" value="1199"/>
  </bean>
</beans>

Ну и наконец создадим загрузчик, который загрузит файл конфигурации и инициирует экспорт службы.


package remoting.server;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloWorldServer {
  public static void main(String[] args) {
    new ClassPathXmlApplicationContext("/remoting/server/applicationContext.xml");
  }
}

Пример клиента RMI службы

RmiProxyFactoryBean - это фабрика, создающая прокси для RMI служб. Ее использование сводится к описанию следующего бина в файле конфигурации Spring:


<bean id="helloWorldService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://localhost:1199/HelloWorldService"/>
<property name="serviceInterface" value="remoting.HelloWorldService"/>
</bean>

Теперь можно использовать бин helloWorldService как и любой другой “не удаленный” бин, передавая его в другие бины в качестве параметров. Я же приведу пример простейшего клиента, получающего ссылку на helloWorldService из фабрики бинов, загружающей описание из файла конфигурации.


package remoting.client;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import remoting.HelloWorldService;

public class HelloWorldClient {
  public static void main(String[] args) {
    final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/remoting/client/applicationContext.xml");

    final HelloWorldService service = (HelloWorldService) context.getBean("helloWorldService", HelloWorldService.class);
    System.out.println(service.sayHello());
  }
}

P.S.

Как видно, Spring framework действительно сильно облегчает работу с удаленными службами. Сегодня я показал, как использовать модель RMI для организации удаленного доступа. В будущем, если в этом есть необходимость, я собираюсь описать использование других моделей, поддерживаемых Spring-ом, а так же рассмотреть преимущества и недостатки разных моделей.
Исходники к данному примеру можно скачать в архиве.

 

5 replies


  1. “В будущем, если в этом есть необходимость, я собираюсь описать использование других моделей, поддерживаемых Spring-ом, а так же рассмотреть преимущества и недостатки разных моделей.”

    Дописал бы. Можно было бы статью в RSDN заслать до публикации здесь.

    Что думаешь?


  2. Допишу.


  3. Интересно посмотреть как это правильно настроить в maven и как запустить на выполнение..


  4. Так же интересно понять, учитывая то, что использование spring позволяет строить приложения подобные тем которые строятся используя ejb - не используя ejb. Например.. на сколько я понял, если создать сервис обернутый в RmiServiceExporter, то этот сервис будет singliton-ом - т.е. аналог stateless-бина (т.е. один для всех).. а как быть если нам нужен аналого statefull-бина. ? (на сколько я понял rmi-сервис всегда будет синглитоном… вопрос - как строить более менее сложные приложения - там где и синглитон и прототайп.. если все так)


  5. Насчет сервиса, то все зависит от того, к какому скопу (scope) его отнести в соответствующем описании бина. По умолчанию - singletom, но спринг никаким образом не ограничивает полет фантазии - можно использовать и prototype, и любые другие custom scope. По поводу мавена - есть есть необходимость, сделаю maven дескриптор, как вернусь из отпуска.

Leave a reply