Clean Code that Works.

http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/remoting.html#remoting-httpinvoker

요약하면, HTTP Invoker를 사용하면 직렬화를 이용해서 원격 호출을 지원할 수 있다.

클라이언트 쪽에서 사용하기 위해서는 당연히 원격 호출을 위한 인터페이스가 필요하다. 이 인터페이스를 포함한 파일들을 서비스를 노출하는 서버에서 제공 해야 된다.(maven으로 jar 파일로 묶어서 클라이언트에 배포, impl은 노출시킬 필요가 없고 필요한 인터페이스만 노출 하면 된다.) 

위에 설정에서 처럼 httpInvokerProxy가 example.AccountService 타입의 bean을 생성해 주기 때문에(프록시로) 클라이언트로 사용할 때는

@Autowired private AccountService service; 형식으로 일반 Spring bean을 사용하는것처럼 사용하면 된다.

물론 내부적으로는 HTTP POST를 통해서 사용되는 거기 때문에 이를 인지하고 있어야 되고, 세부적인 설정이 필요 하다면 commons HttpClient를 httpInvokerRequestExecutor로 지정한 후에 여러가지 세팅을 지정할수 있다(timeout, connection pooling, 인증 등)

스프링에서 제공하는 remoting 기능중에 HTTP invokers 를 사용하는 방법이 있다.(위 문서를 간단히 번역, 날림 번역)

Burlap 과 Hessian을 사용하여 remoting 기능을 사용할 수 있지만 이 방법은 표준이 아닌 가벼운 프로토콜을 사용하여 자기들만의 직렬화 방식을 사용한다.

Spring Http Invokers HTTP를 통해 서비스를 노출하기 위해 자바 표준 직렬화 기능을 사용한다. 이것은 파라미터나 리턴타입이 복잡하고 Hessian 이나 Burlap의 직렬화 기법이 동작하지 않을때 큰 이점이 있다. 

스프링은 J2SE에서 제공하는 표준 HTTP 호출이나 Commons HttpClient 를 사용한다. Commons HttpClient를 사용하는게 기능적으로 쉽고 좀 더 많은 이점이 있다. 이 링크를 참조 jakarta.apache.org/commons/httpclient 

서비스 오브젝트 노출하기.

스프링 HttpInvoker는 org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter를 제공한다. 

AccountService 를 스프링 웹 MVC DispatcherServlet을 통해 노출시키기 위해서는 dispatcher의 application context에 아래와 같은 설정을 추가 해야 된다.

<bean name="/AccountService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter"> <property name="service" ref="accountService"/>     <property name="serviceInterface" value="example.AccountService"/> </bean>

이 방식은 DispathcerServlet의 표준 매핑 방식에 따라 매핑된다.

다른 방법은 HttpInvokerServiceExporter를 root application에 만들 수 있다(e.g 'WEB-INF/applicationContext.xml')

<bean name="accountExporter" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">     <property name="service" ref="accountService"/>     <property name="serviceInterface" value="example.AccountService"/> </bean>

추가적으로 이것과 통신하기 위한 exporter를 'web.xml'에 정의 해야 하고, 서블릿의 이름은 exporter와 일치 해야 한다. 

<servlet>
    <servlet-name>accountExporter</servlet-name>
    <servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>accountExporter</servlet-name>
    <url-pattern>/remoting/AccountService</url-pattern>
</servlet-mapping>

만약 서블릿 컨테이너를 사용하지 않고 Sun's Java 6를 사용한다면 내장된 HTTP servier implementation을 사용할수 있다.(이런것도 있었나) SimpleHttpServerFactoryBean과 함계 SImpleHttpInvokerServiceExporter를 아래의 예제처럼 사용하면 된다.

<bean name="accountExporter"
    class="org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter">
    <property name="service" ref="accountService"/>
    <property name="serviceInterface" value="example.AccountService"/>
</bean>

<bean id="httpServer"
        class="org.springframework.remoting.support.SimpleHttpServerFactoryBean">
    <property name="contexts">
        <util:map>
            <entry key="/remoting/AccountService" value-ref="accountExporter"/>
        </util:map>
    </property>
    <property name="port" value="8080" />
</bean>


서비스를 클라이언트와 연결하기.

프록시를 사용해서, 스프링은 당신의 요청을 HTTP POST requests로 변환하여 노출된 서비스를 가르키는 URL로 가게 해준다.

<bean id="httpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
    <property name="serviceUrl" value="http://remotehost:8080/remoting/AccountService"/>
    <property name="serviceInterface" value="example.AccountService"/>
</bean>

전에 언급한 바와 같이 HTTP client는 원하는 것을 사용할 수 있다. J2SE HTTP 를 사용하는 HttpInvokerProxy가 기본으로 지정되어 있지만 httpInvokerRequestExecuttor 속성에 Commons HttpClient를 세팅해서 사용할 수도 있다.

<property name="httpInvokerRequestExecutor">
    <bean class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"/>
</property>


기술을 선택할때의 고려사항

여기에서 제시된 각각의 기술은 단점이 있다. 

RMI를 사용할때 RMI 트래픽을 터널링 하지 않는한  HTTP protocol을 통해 객체에 접근할수 없다. RMI는 완전한 객체 직렬화를 지원하는 상당히 무거운 프로토콜 이지만 정보를 통해 직렬화가 필요한 복합 데이터 모델을 사용할때 중요하다. 하지만, RMI-JRMPs는 Java 클라이언트에 종속적이 된다. 이것은 Java-to-Java간의 원격 호출 방식이다.

Spring에서 제공하는 HTTP invoker는 HTTP 기반의 원격호출을 사용하지만 자바 직렬화가 필요할때 사용할 수 있는 좋은 선택이다. 이것은 RMI invoker의 기본 구조를 공유하고 HTTP를 전송하기 위해서만 사용된다. HTTP invoker는 Java-to-Java 에 제한을 두진 않지만 클라이언트와 서버 둘다 스프링을 사용해야 된다.

Hessian 이나 Burlap은 이기종 환경에서 사용할때 큰 이점이 있다. 왜냐하면 이들은 명시적으로 Java Clinet가 아닌것도 사용가능하기 때문이다. 하지만 Java Clinet가 아닌것을 지원하는데는 여전히 제한이 있다. 알려진 이슈로는 늦은 초기화 콜렉션이 포함된 하이버네이트 객체를 직렬화 하는것에대한 문제가 있다. 만약 이런 구조의 데이터 모델을 가지고 있다면 Hessian의 대용으로 RMI나 HTTP invoker를 사용하는것을 고려할 수 있다.

JMS는 서비스들을 클러스터링하기에 용이하고 JMS 브로커를 통해 로드 벨런싱을 하게 하거나 자동 오류극복을 하게 할 수 있다. 기본적으로 JMS를 사용할때 자바의 직렬화를 사용하도록 되어 있지만 JMS provider는 XStream을 구현하거나 다른 방식을 구현한 것처럼 다른 메커니즘을 가진 방식을 사용할 수 있다.

마지막으로 가장 적게 사용되는건 아니지만 EJB는 RMI를 넘어서는 표준 role-based 인증민 인가, 원격 트랜잭션 전파를 지원하는 장점이 있다. 스프링의 핵심 기능에서 제공되지는 않지만 원격 보안 컨텍스트 전파를 지원하는 RMI Invoker나 HTTP Invoker를 통해 얻을 수 있다.