본문 바로가기

Spring

Spring RMI 사용하기..


Spring RMI를 사용해보기 위해 간단한 클래스들을 작성해 보았다..

꽤나 삽질 많이 했다..ㅠㅠ

기선님의 블로그에 있는 내용을 보고 작성해 보았는데도 시간이 꽤 걸리더라는...

일단, 서비스를 제공하는 측의 Service 클래스를 만들어보자..

RMISearchService.java

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public interface RMISearchService {
 Log logger = LogFactory.getLog(RMISearchService.class);
 
 String search(String keyword);
}


 

RMISearchServiceImpl.java

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class RMISearchServiceImpl implements RMISearchService {
 Log logger = LogFactory.getLog(RMISearchServiceImpl.class);

 @Override
 public String search(String keyword) {

  logger.debug("call service keyword : " + keyword);
  
  return keyword;
 }
}


단순히 keyword를 받아서 그 keyword를 리턴하는 서비스 클래스이다. 이렇게 작성을 한 후 xml에 설정을 해주어야 한다.

applicationContext.xml
 
<bean id="rmiSearchService"
  class="gseshop.u2search.service.RMISearchServiceImpl">
 </bean>
 
 <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
  <property name="service" ref="rmiSearchService" />
  <property name="serviceName" value="SearchService"></property>
  <property name="serviceInterface" value="gseshop.u2search.service.RMISearchService"></property>
 </bean>


service 는 실제로 서비스를 구현한 클래스의 id가 되고
serviceName은 클라이언트측에서 호출 할 서비스의 이름이 된다.
serviceInterface는 서비스를 구현한 클래스가 implements 하고 있는 인터페이스가 되고
이 인터페이스는 client측에 제공되어야 한다.

이 외에도 registryPort 와 servicePort도 지정해 줄 수 있다.

이정도면 서비스 제공측에서는 준비가 끝났다.

이제 클라이언트측을 작성해 보자..


RMICallService.java

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public interface RMICallService {
 Log logger = LogFactory.getLog(RMICallService.class);
 
 String call(String keyword);
}



 

 

RmiCallServiceImpl.java

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class RmiCallServiceImpl implements RMICallService {
 Log logger = LogFactory.getLog(RmiCallServiceImpl.class);
 
 RMISearchService rmiSearchService;
 
 public void setRmiSearchService(RMISearchService rmiSearchService) {
  this.rmiSearchService = rmiSearchService;
 }
 
 public String call(String keyword) {
  return rmiSearchService.search(keyword);
 }
}



 

 

마찬가지로 RMI를 통해 원격의 서비스를 호출하고 그 결과를 리턴하는 간단한 서비스 객체이다.
저 위에 굵게 표시된 부분을 보면, RMI를 통해 원격 호출을 하기 위해 서비스 제공측의 인터페이스를
가지고 있는 것을 알게 된다. 위에서 얘기한 서비스 제공측의 인터페이스가 제공되어야 하는 이유이다.

그리고 웹에서의 사용을 위해 이 클라이언트측 서비스를 호출 할 컨트롤러를 작성해보자..

 
RemoteCallController.java

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import gseshop.u2si.service.RMICallService;

@Controller
public class RemoteCallController {
 Log logger = LogFactory.getLog(RemoteCallController.class);
 
 RMICallService rmiCallService;
 
 @Autowired
 public void setRMICallService(RMICallService rmiCallService) {
  this.rmiCallService = rmiCallService;
 }
 
 @RequestMapping("/rmicall.gs")
 public String search(HttpServletRequest request, HttpServletResponse response) {
  logger.debug("controll.....");
  
  String keyWord = request.getParameter("keyword");
  String result = rmiCallService.call(keyWord);
  
  ModelAndView mv = new ModelAndView();
  mv.setViewName("result");
  
  return result;
 }
}



어노테이션을 사용했지만 사실 어노테이션을 사용하면 (심지어 서비스 객체도 @Service를 사용하면 XML 정의가 필요 없다) 코딩은 많이 편한데... 나중에 관리 차원에서는.. 좀 어렵지 않을까 싶기도 하다.. 일단 그래도 어노테이션으로...

그럼 이 controller를 테스트 할 테스트 객체를 만들자..

RmiCallServiceImplTest.java


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;

public class RmiCallServiceImplTest extends AbstractDependencyInjectionSpringContextTests {
 Log logger = LogFactory.getLog(RmiCallServiceImplTest.class);
 
 @Override
 protected String[] getConfigLocations() {
  return new String[] {"classpath:actions/action-config.xml","classpath:services/serviceContext-sample.xml"};
 }
 
 private RemoteCallController rcc;
 
 public void setRemoteCallController(RemoteCallController rcc) {
  this.rcc = rcc;
 }
 
 public void testCall() throws Exception {
  MockHttpServletRequest request = new MockHttpServletRequest();
  MockHttpServletResponse response = new MockHttpServletResponse();
  
  request.setParameter("keyword", "나이키");
  String result = rcc.search(request, response);
  assertEquals("나이키",result);
 }
}



 

AbstractDependencyInjectionSpringContextTests를 상속받아서 구현해 보았다.
앞선 포스트에도 작성했지만 getConfigLocations()  메서드를 통해서 자동적으로 설정되어 있는 bean들을
바인딩 해온다.

Controller가 가지고 있는 Service 객체들 까지..

이제 클라이언트측 XML 설정을 해보면..


applicationContext.xml 

<bean id="rmiCall" class="gseshop.u2si.service.RmiCallServiceImpl" >
  <property name="rmiSearchService" ref="rmiSearchService1" />
 </bean>

 <bean id="rmiSearchService1"
  class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
  <property name="serviceUrl"
   value="rmi://localhost/SearchService" />
  <property name="serviceInterface"
   value="gseshop.u2si.service.RMISearchService" />
 </bean>


rmiCall은 클라이언트측에서 RMI 호출을 할 객체이다. 이녀석이 실제로 서비스 제공측의 인터페이스를 가지고 있으므로 그녀석을 Injection 시키기 위해서 property로 지정되어 있다. (rmiSearchService1)

rmiSearchService1은
아래에 설정이 되어 있는데 이 설정을 통해서 RMI를 통해 원격에 있는 RMISearchService의 메서드를 호출 할 수 있게 된다.

테스트를 해보고 실제 서버를 띄워서 해보자..

~~


이참에 봐도봐도 까먹는 자바 RMI를 한번 더 읽어봐야겠다.. 아 이 메멘토 머리통..