Spring RMI를 사용해보기 위해 간단한 클래스들을 작성해 보았다..
꽤나 삽질 많이 했다..ㅠㅠ
기선님의 블로그에 있는 내용을 보고 작성해 보았는데도 시간이 꽤 걸리더라는...
일단, 서비스를 제공하는 측의 Service 클래스를 만들어보자..
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에 설정을 해주어야 한다.
<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도 지정해 줄 수 있다.
이정도면 서비스 제공측에서는 준비가 끝났다.
이제 클라이언트측을 작성해 보자..
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를 통해 원격 호출을 하기 위해 서비스 제공측의 인터페이스를
가지고 있는 것을 알게 된다. 위에서 얘기한 서비스 제공측의 인터페이스가 제공되어야 하는 이유이다.
그리고 웹에서의 사용을 위해 이 클라이언트측 서비스를 호출 할 컨트롤러를 작성해보자..
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를 테스트 할 테스트 객체를 만들자..
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);
}
}
앞선 포스트에도 작성했지만 getConfigLocations() 메서드를 통해서 자동적으로 설정되어 있는 bean들을
바인딩 해온다.
Controller가 가지고 있는 Service 객체들 까지..
이제 클라이언트측 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의 메서드를 호출 할 수 있게 된다.
테스트를 해보고 실제 서버를 띄워서 해보자..
~~