Статьи

Поддержка Spring Remoting и разработка RMI Service

Разработка сервисов с удаленной поддержкой облегчается благодаря поддержке удаленного взаимодействия Spring. В настоящее время Spring поддерживает следующие технологии удаленного взаимодействия: удаленный вызов методов (RMI), HTTP Invoker, Hessian, Burlap, JAX-RPC, JAX-WS и JMS.

Удаленный вызов метода (RMI) : Spring поддерживает RMI через RmiProxyFactoryBean и RmiServiceExporter. RmiServiceExporter экспортирует любой управляемый Spring компонент в качестве службы RMI и регистрирует. RmiProxyFactoryBean — это фабричный компонент, создающий прокси для службы RMI. Этот прокси-объект взаимодействует с удаленными службами RMI от имени клиента.

HTTP-инициатор Spring : Spring-HTTP-инициаторы используют стандартный механизм сериализации Java для предоставления сервисов через HTTP. Spring поддерживает инфраструктуру HTTP invoker через HttpInvokerProxyFactoryBean и HttpInvokerServiceExporter. HttpInvokerServiceExporter, который экспортирует указанный компонент службы в качестве конечной точки службы HTTP invoker, доступный через прокси HTTP invoker. HttpInvokerProxyFactoryBean — это фабричный компонент для прокси-серверов HTTP invoker.

Hessian: Hessian предлагает двоичный протокол удаленного взаимодействия на основе HTTP. Spring поддерживает Hessian через HessianProxyFactoryBean и HessianServiceExporter.

Мешковина: Мешковина — основанная на XML альтернатива Коши Гессиану. Spring предоставляет классы поддержки, такие как BurlapProxyFactoryBean и BurlapServiceExporter.

JAX-RPC: Spring обеспечивает поддержку удаленного взаимодействия для веб-служб через JAX-RPC (API веб-службы J2EE 1.4).

JAX-WS: Spring обеспечивает поддержку удаленного взаимодействия для веб-служб через JAX-WS (преемник JAX-RPC, представленный в Java EE 5 и Java 6).

JMS: поддержка удаленного взаимодействия JMS в Spring предоставляется классами JmsInvokerServiceExporter и JmsInvokerProxyFactoryBean.

Давайте посмотрим на поддержку Spring RMI для разработки Spring RMI Service & Client.

Используемые технологии:

JDK 1.6.0_31
Весна 3.1.1
Maven 3.0.2

ШАГ 1: СОЗДАТЬ MAVEN ПРОЕКТ

Maven проект создается как показано ниже. (Его можно создать с помощью Maven или IDE Plug-in).

ШАГ 2: БИБЛИОТЕКИ

Spring-зависимости добавляются в pom.xml Maven.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<!-- Spring 3.1.x dependencies -->
<properties>
    <spring.version>3.1.1.RELEASE</spring.version>
</properties>
  
<dependencies>
            <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
<dependencies>

ШАГ 3: СОЗДАЙТЕ ПОЛЬЗОВАТЕЛЬСКИЙ КЛАСС

Новый класс пользователя создан.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package com.otv.user;
  
import java.io.Serializable;
  
/**
 * User Bean
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class User implements Serializable {
  
    private long id;
    private String name;
    private String surname;
  
    /**
     * Get User Id
     *
     * @return long id
     */
    public long getId() {
        return id;
    }
  
    /**
     * Set User Id
     *
     * @param long id
     */
    public void setId(long id) {
        this.id = id;
    }
  
    /**
     * Get User Name
     *
     * @return long id
     */
    public String getName() {
        return name;
    }
  
    /**
     * Set User Name
     *
     * @param String name
     */
    public void setName(String name) {
        this.name = name;
    }
  
    /**
     * Get User Surname
     *
     * @return long id
     */
    public String getSurname() {
        return surname;
    }
  
    /**
     * Set User Surname
     *
     * @param String surname
     */
    public void setSurname(String surname) {
        this.surname = surname;
    }
  
    @Override
    public String toString() {
        StringBuilder strBuilder = new StringBuilder();
        strBuilder.append("Id : ").append(getId());
        strBuilder.append(", Name : ").append(getName());
        strBuilder.append(", Surname : ").append(getSurname());
        return strBuilder.toString();
    }
}

ШАГ 4: СОЗДАЙТЕ ИНТЕРФЕЙС ICacheService

Интерфейс ICacheService, представляющий интерфейс службы удаленного кэша, создан.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.otv.cache.service;
  
import java.util.concurrent.ConcurrentHashMap;
  
import com.otv.user.User;
  
/**
 * Cache Service Interface
 *
 * @author  onlinetechvision.com
 * @since   27 Feb 2012
 * @version 1.0.0
 *
 */
public interface ICacheService {
  
    /**
     * Get User Map
     *
     * @return ConcurrentHashMap User Map
     */
    public ConcurrentHashMap<long, user> getUserMap();
  
}

ШАГ 5: СОЗДАЙТЕ CacheService CLASS

Класс CacheService создается путем реализации интерфейса ISchedulerService. Предоставляет доступ к удаленному кешу…

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.otv.cache.service;
  
import java.util.concurrent.ConcurrentHashMap;
  
import com.otv.user.User;
  
/**
 * Cache Service Implementation
 *
 * @author  onlinetechvision.com
 * @since   6:04:49 PM
 * @version 1.0.0
 *
 */
public class CacheService implements ICacheService {
  
    //User Map is injected...
    ConcurrentHashMap<long, user> userMap;
  
    /**
     * Get User Map
     *
     * @return ConcurrentHashMap User Map
     */
    public ConcurrentHashMap<long, user> getUserMap() {
        return userMap;
    }
  
    /**
     * Set User Map
     *
     * @param ConcurrentHashMap User Map
     */
    public void setUserMap(ConcurrentHashMap<long, user> userMap) {
        this.userMap = userMap;
    }
  
}

ШАГ 6: СОЗДАЙТЕ ИНТЕРФЕЙС IRMIUserService

IRMIUserService Интерфейс, представляющий интерфейс службы RMI, создан. Кроме того, он предоставляет удаленные методы для клиентов RMI …

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.otv.rmi.server;
  
import java.util.List;
  
import com.otv.user.User;
  
/**
 * RMI User Service Interface
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public interface IRMIUserService {
  
    /**
     * Add User
     *
     * @param  User user
     * @return boolean response of the method
     */
    public boolean addUser(User user);
  
    /**
     * Delete User
     *
     * @param  User user
     * @return boolean response of the method
     */
    public boolean deleteUser(User user);
  
    /**
     * Get User List
     *
     * @return List user list
     */
    public List<User> getUserList();
  
}

ШАГ 7: СОЗДАЙТЕ RMIUserService CLASS

Класс RMIUserService (он же объект RMI) создается путем реализации интерфейса IRMIUserService.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package com.otv.rmi.server;
  
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
  
import com.otv.cache.service.ICacheService;
import com.otv.user.User;
  
/**
 * RMI User Service Implementation
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class RMIUserService implements IRMIUserService {
  
    private static Logger logger = Logger.getLogger(RMIUserService.class);
  
    //Remote Cache Service is injected...
    ICacheService cacheService;
  
    /**
     * Add User
     *
     * @param  User user
     * @return boolean response of the method
     */
    public boolean addUser(User user) {
        getCacheService().getUserMap().put(user.getId(), user);
        logger.debug("User has been added to cache. User : "+getCacheService().getUserMap().get(user.getId()));
        return true;
    }
  
    /**
     * Delete User
     *
     * @param  User user
     * @return boolean response of the method
     */
    public boolean deleteUser(User user) {
        getCacheService().getUserMap().put(user.getId(), user);
        logger.debug("User has been deleted from cache. User : "+user);
        return true;
    }
  
    /**
     * Get User List
     *
     * @return List user list
     */
    public List<User> getUserList() {
        List<User> list = new ArrayList<User>();
        list.addAll(getCacheService().getUserMap().values());
        logger.debug("User List : "+list);
        return list;
    }
  
    /**
     * Get RMI User Service
     *
     * @return IRMIUserService RMI User Service
     */
    public ICacheService getCacheService() {
        return cacheService;
    }
  
    /**
     * Set RMI User Service
     *
     * @param IRMIUserService RMI User Service
     */
    public void setCacheService(ICacheService cacheService) {
        this.cacheService = cacheService;
    }
}

ШАГ 8: СОЗДАТЬ RMIServerStarter CLASS

RMI Server Starter Class создан. Запускает сервер RMI.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
package com.otv.rmi.server.starter;
  
import org.springframework.context.support.ClassPathXmlApplicationContext;
  
/**
 * RMI Server Starter
 *
 * @author  onlinetechvision.com
 * @since   27 Feb 2012
 * @version 1.0.0
 *
 */
public class RMIServerStarter {
  
    public static void main(String[] args) {
  
        //RMI Server Application Context is started...
        new ClassPathXmlApplicationContext("rmiServerAppContext.xml");
    }
}

ШАГ 9: СОЗДАТЬ rmiServerAppContext.xml

Содержимое контекста приложения сервера RMI показано ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  
  
    <!-- Beans Declaration -->
    <bean id="UserMap" class="java.util.concurrent.ConcurrentHashMap" />
  
    <bean id="CacheService" class="com.otv.cache.service.CacheService">
        <property name="userMap" ref="UserMap"/>
    </bean>  
  
    <bean id="RMIUserService" class="com.otv.rmi.server.RMIUserService" >
        <property name="cacheService" ref="CacheService"/>
    </bean>
  
    <!-- RMI Server Declaration -->
    <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
  
        <!-- serviceName represents RMI Service Name -->
        <property name="serviceName" value="RMIUserService"/>
  
        <!-- service represents RMI Object(RMI Service Impl) -->
        <property name="service" ref="RMIUserService"/>
  
        <!-- serviceInterface represents RMI Service Interface exposed -->
        <property name="serviceInterface" value="com.otv.rmi.server.IRMIUserService"/>
  
        <!-- defaults to 1099 -->
        <property name="registryPort" value="1099"/>
  
   </bean>
  
</beans>

ШАГ 10: СОЗДАТЬ RMIServiceClient CLASS

Класс RMIServiceClient создан. Он вызывает службу пользователя RMI и выполняет пользовательские операции.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.otv.rmi.client;
  
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
  
import com.otv.rmi.server.IRMIUserService;
import com.otv.rmi.server.RMIUserService;
import com.otv.user.User;
  
/**
 * RMI Service Client
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class RMIServiceClient {
  
    private static Logger logger = Logger.getLogger(RMIUserService.class);
  
    /**
     * Main method of the RMI Service Client
     *
     */
    public static void main(String[] args) {
  
        logger.debug("RMI Service Client is starting...");
  
        //RMI Client Application Context is started...
        ApplicationContext context = new ClassPathXmlApplicationContext("rmiClientAppContext.xml");
  
        //Remote User Service is called via RMI Client Application Context...
        IRMIUserService rmiClient = (IRMIUserService) context.getBean("RMIUserService");
  
        //New User is created...
        User user = new User();
        user.setId(1);
        user.setName("Bruce");
        user.setSurname("Willis");
  
        //The user is added to the remote cache...
        rmiClient.addUser(user);
  
        //The users are gotten via remote cache...
        rmiClient.getUserList();
  
        //The user is deleted from remote cache...
        rmiClient.deleteUser(user);
  
        logger.debug("RMI Service Client is stopped...");
    }
}

ШАГ 11: СОЗДАТЬ rmiClientAppContext.xml

Содержимое контекста клиентского приложения RMI показано ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
  
  
    <!-- RMI Client Declaration -->
    <bean id="RMIUserService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
  
        <!-- serviceUrl represents RMI Service Url called-->
        <property name="serviceUrl" value="rmi://x.x.x.x:1099/RMIUserService"/>
  
        <!-- serviceInterface represents RMI Service Interface called -->
        <property name="serviceInterface" value="com.otv.rmi.server.IRMIUserService"/>
  
        <!-- refreshStubOnConnectFailure enforces automatic re-lookup of the stub if a
                            call fails with a connect exception -->
        <property name="refreshStubOnConnectFailure" value="true"/>
  
    </bean>
  
</beans>

ШАГ 12: ЗАПУСК ПРОЕКТА

Если RMI Service Client запускается при запуске RMI Server, ниже будут показаны журналы вывода RMI Server. Кроме того, RMI-сервер и клиент можно запустить, открыв две отдельные консоли через вашу IDE. :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
....
04.03.2012 14:23:15 DEBUG (RmiBasedExporter.java:59) - RMI service [com.otv.rmi.server.RMIUserService@16dadf9] is an RMI invoker
04.03.2012 14:23:15 DEBUG (JdkDynamicAopProxy.java:113) - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.otv.rmi.server.RMIUserService@16dadf9]
04.03.2012 14:23:15  INFO (RmiServiceExporter.java:276) - Binding service 'RMIUserService' to RMI registry: RegistryImpl[UnicastServerRef [liveRef: [endpoint:[192.168.1.7:1099](local),objID:[0:0:0, 0]]]]
04.03.2012 14:23:15 DEBUG (AbstractAutowireCapableBeanFactory.java:458) - Finished creating instance of bean 'org.springframework.remoting.rmi.RmiServiceExporter#0'
04.03.2012 14:23:15 DEBUG (AbstractApplicationContext.java:845) - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@3c0007]
04.03.2012 14:23:15 DEBUG (AbstractBeanFactory.java:245) - Returning cached instance of singleton bean 'lifecycleProcessor'
  
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:73) - Incoming RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.addUser
04.03.2012 14:25:43 DEBUG (RMIUserService.java:33) - User has been added to cache. User : Id : 1, Name : Bruce, Surname : Willis
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:79) - Finished processing of RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.addUser
  
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:73) - Incoming RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.getUserList
04.03.2012 14:25:43 DEBUG (RMIUserService.java:57) - User List : [Id : 1, Name : Bruce, Surname : Willis]
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:79) - Finished processing of RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.getUserList
  
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:73) - Incoming RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.deleteUser
04.03.2012 14:25:43 DEBUG (RMIUserService.java:45) - User has been deleted from cache. User : Id : 1, Name : Bruce, Surname : Willis
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:79) - Finished processing of RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.deleteUser
  
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:73) - Incoming RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.getUserList
04.03.2012 14:25:43 DEBUG (RMIUserService.java:57) - User List : []
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:79) - Finished processing of RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.getUserList

ШАГ 13: СКАЧАТЬ

OTV_SpringRMI

Справка: поддержка Spring Remoting и разработка службы RMI от нашего партнера JCG Эрен Авсарогуллари в блоге Online Technology Vision .