본문 바로가기

Spring

Spring HTTP Invoker

엊그제 인가 작성한  spring rmi 포스트에 이어서..
친구가 얘기한 http invoker도 한번 해보았다..

이쪽은 이상하게 웹에 예제가 많지 않더라... 음.. 왜 그러지..

일단, http invoker는 stream을 사용하여 객체를 주고 받는 형식으로 되어 있는 듯 하다.
httpclient.. 예전에 풍대리님께서 가르쳐주신 그러한 비슷한 방법을 사용하는 듯..

일단 해보는 것이 목적이기 때문에..
작성을 해보았다.

service 제공 측. (server)

HttpInvokerSearchService.java

public interface HttpInvokerSearchService {
 Log logger = LogFactory.getLog(HttpInvokerSearchService.class);
 
 HashMap<String,String> search(String keyword);
}

 

HttpInvokerSearchServiceImpl.java

public class HttpInvokerSearchServiceImpl implements HttpInvokerSearchService {
 Log logger = LogFactory.getLog(HttpInvokerSearchServiceImpl.class);

 @Override
 public HashMap<String,String> search(String keyword) {

  logger.warn("call service keyword : " + keyword);
  
  HashMap<String,String> resultMap = new HashMap<String,String>();
  resultMap.put("result", keyword);
  
  return resultMap;
 }
}



간단한 서비스 빈을 하나 만든다. keyword를 받아서 keyword를 HashMap에 "result"라는 키로 담아서 리턴한다.
직렬화를 구현 할 필요가 없다.

http invoker를 사용하게 위해서는 서비스를 제공하는 측에 dispatcherservlet을 하나 더 생성 한다.
물론 기존의 dispatcher servlet에 합쳐도 작동은 한다.


web.xml 

<!-- http invoker -->
 <servlet>
     <servlet-name>httpinvoker</servlet-name>
     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
     <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/spring/actions/httpinvoker*.xml</param-value>
  </init-param>
 </servlet>

 <servlet-mapping>
     <servlet-name>action</servlet-name>
     <url-pattern>/http/*</url-pattern>
 </servlet-mapping>
 <!--// http invoker -->



이렇게 dispatcherservlet을 하나더 생성하고, 해당 경로에 httpinvoker-config.xml 이라는 파일을 작성한다.

httpinvoker-config.xml 
 
<!-- Http Invoker -->
 <bean id="httpInvokerService"
  class="gseshop.u2search.service.HttpInvokerSearchServiceImpl">
 </bean>
 
 <bean name="/HttpSearchService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
  <property name="service" ref="httpInvokerService" />
  <property name="serviceInterface" value="gseshop.u2search.service.HttpInvokerSearchService" />
 </bean>
 <!-- // Http Invoker -->


디폴트로 org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping를 사용하게 될 것이다.

만약에 기존의 dispatcherserlvet에 추가 하고 싶다면 web.xml에
 

<!-- http invoker -->
 <servlet-mapping>
     <servlet-name>action</servlet-name>
     <url-pattern>/http/*</url-pattern>
 </servlet-mapping>
 <!--// http invoker -->


이렇게 추가하고, action-config.xml에 위(httpinvoker-config.xml 의) 설정을 해주면된다. 이 경우에 uri가 bean name="/HttpSearchService" 로 mapping 이 될 수 있도록 BeanNameUrlHandlerMapping를 사용하여 mapping 해주어야 한다.

이미 사용하고 있는 HandlerMapping이 있다면

    <bean id="beanNameUrlMapper"
        class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
        <property name="order" value="2" />
    </bean>

이렇게 설정해 주자.


이렇게 해주면 서버측에서 해야 할 작업은 끝났다.
이 서버측 서비스 호출은 http://local:port/app-name/http/HttpSearchService 로 호출되게 된다.


Client측.
서비스를 요청하는 측에 대한 작업을 해보자..

일단 위에서 작성한 인터페이스(HttpInvokerSearchService.java)를 가지고 있어야 한다. (Spring RMI와 같은 이유로..)

원격 서비스를 call하는 client측 은 아래와 같다.
 

HttpInvokerSearchServiceClient.java

public class HttpInvokerSearchServiceClient {
 Log logger = LogFactory.getLog(HttpInvokerSearchServiceClient.class);
 
  private HttpInvokerSearchService serverService;
 
  @Autowired
  public void setServerService(HttpInvokerSearchService serverService) {
   this.serverService = serverService;
  }


 
  public HashMap<String,String> doSomething(String keyword) {
   HashMap<String,String> resultMap = serverService.search(keyword);
  
   logger.info("RESULT : " + resultMap);
  
   return resultMap;
  }
}



 
위에서 Autowired로 set 해주고 있는 클래스가 서버측에서 제공된 인터페이스이다.

이를 위한 설정은 아래와 같다.

applicationContext.xml
 
<!-- spring http invoker client -->
 <bean id="searchServiceHttpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
    <property name="serviceUrl" value="http://localhost:8889/http/HttpSearchService"/>
    <property name="serviceInterface" value="gseshop.u2si.service.HttpInvokerSearchService"/>
  </bean>
 
  <bean id="httpInvokerSearchServiceClient" class="gseshop.u2si.service.HttpInvokerSearchServiceClient" >
    <property name="serverService" ref="searchServiceHttpInvokerProxy" />
  </bean>
 <!--// spring http invoker client -->

 

보면 알겠지만....

httpInvokerSearchServiceClient가 가지고 있는 HttpInvokerSearchService객체를 injection 하기 위한 설정이다. 위 설정을 통해서 HttpInvokerSearchService 클래스를 통하여 원격에 있는 메서드를 호출 할 수 있게 된다.

간단한 테스트 클래스를 만들어보면..

HttpInvokeSearchServiceClientTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:config/applicationContext.xml",
 "classpath:actions/action-config.xml",
 "classpath:services/serviceContext-sample.xml" })
public class HttpInvokeSearchServiceClientTest {
 Log logger = LogFactory.getLog(HttpInvokeSearchServiceClientTest.class);
 
 @Autowired
 private HttpInvokerSearchServiceClient httpInvokerSearchServiceClient;
 
 @Test
 public void testService() {
  MockHttpServletRequest request = new MockHttpServletRequest();
  MockHttpServletResponse response = new MockHttpServletResponse();
  
  
  HashMap<String, String> resultMap = httpInvokerSearchServiceClient.doSomething("TEST NIKE");
    
  logger.info("Test Result : " + resultMap);
  
  assertEquals(resultMap.get("result"),"TEST NIKE");
 }
}


이렇게 해서 위에서 설정한 httpInvokerSearchServiceClient를 injection하여 원격 메서드를 호출해 볼 수 있다.

일단 클라이언트측에서 해야 할 일이 많지 않고..
rmi보다 가벼운거 같다. 하지만 어디서 본거 같은데...
양측이 모두 spring을 사용하고 있어야지만 사용 할 수 있다고 한다.