5.HTTP Invoker

HTTP Invoker는 HTTP를 통해 경량의 원격 서비스를 가능하게 하는 Spring에서 제공하는 Remoting 기능이다. 앞서 소개한 RMI와 Hessian/Burlap의 경우 아래와 같은 단점이 있는데 이러한 단점을 보완해주는 기능을 HTTP Invoker가 가지고 있다.

  • RMI 단점: RMI의 경우 자바의 표준 객체 직렬화를 사용하지만 방화벽을 통과하기가 어렵다.

  • Hessian/Burlap의 단점: 방화벽을 쉽게 통과하지만, 자체적인 객체 직렬화 매커니즘을 사용하여 복잡한 형태의 객체 직렬화 시 문제가 발생할 수 있다.

HTTP Invoker는 RMI와 Hessian/Burlap의 단점을 보완해준다. Spring에서 제공하는 Remoting 기능으로 HTTP를 통해 Remoting 기능을 수행하며 자바의 표준 직렬화 매커니즘을 사용한다. 단, Spring에서만 제공하는 Remoting 기술로 클라이언트와 원격 서비스 모두 Spring 어플리케이션 이어야 한다.

다음은 HTTP Invoker 기능을 Server와 Client 단에서 어떻게 사용해야 하는지에 대한 사용법이다.

5.1.Server Configuration

서버 구현 방식은 일반 서비스 빈 개발 방식과 같으며 HttpInvokerServiceExporter 클래스를 이용하여 손쉽게 일반 Spring Bean으로 작성된 서비스를 HTTP Invoker Service로 노출시킬 수 있다. 이때 모든 public 메소드는 서비스 메소드로 노출된다.

Property NameDescriptionRequiredDefault Value
serviceHTTP Invoker 서비스로 노출시키고 싶은 Spring Bean의 id를 설정한다.YN/A
serviceInterfaceHTTP Invoker 서비스로 노출되는 서비스의 인터페이스 클래스를 패키지정보와 함께 작성한다.YN/A

5.1.1.Samples

다음은 HTTP Invoker 서버 구현 속성 설정에 대한 예제이다. 서비스는 일반 Spring Bean 개발과 동일하며 HttpInvokerServiceExporter Bean에서 property 설정 정보를 참조하여 HTTP Invoker 서비스로 노출시키고 있다.

  • Configuration

    다음은 HTTP Invoker 서비스를 지원하는 HttpInvokerServiceExporter의 속성을 정의한 context-remoting.xml 의 일부이다.

    <bean id="remotingProductService" 
            class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="productService"/>
        <property name="serviceInterface" 
                value="anyframe.sample.remoting.sales.service.ProductService" />
    </bean>

    여기서 HttpInvokerServiceExporter 빈은 Spring MVC의 컨트롤러로 작성되어 있으므로 Spring MVC의 DispatcherServlet을 web.xml 파일에 설정해야 한다. HTTP로 서비스를 제공하기 위해서 웹 어플리케이션으로 서비스를 배포하여 제공하고 있다. 다음은 서버 사이드 웹 어플리케이션의 web.xml 의 일부이다.

    <web-app id="WebApp_ID" version="2.4"
        xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
        <display-name>sample-web</display-name>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath:/spring/context-*.xml
            </param-value>
        </context-param>
        
        ...중략...
    
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener
            </listener-class>
        </listener>
        
        <servlet>
            <servlet-name>action</servlet-name>
            <servlet-class>
                org.springframework.web.servlet.DispatcherServlet
            </servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:/springmvc/*-servlet.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        
        <servlet-mapping>
            <servlet-name>action</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
        
        <!-- remoting-configuration-START -->  
        <servlet>
            <servlet-name>remoting</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:/springmvc/remoting-servlet.xml</param-value>
            </init-param>
        </servlet>    
        
        <servlet-mapping>
            <servlet-name>remoting</servlet-name>
            <url-pattern>/remoting/*</url-pattern>
        </servlet-mapping>    
        <!-- remoting-configuration-END -->
        ...중략...
    </web-app>

    여기서 Spring MVC의 URL Mapping 기능을 사용하여 HTTP 기반의 HTTP Invoker 컨트롤러를 호출할 수 있도록 한다. 다음은 서버 사이드 웹 어플리케이션의 remoting-servlet.xml 의 일부이다. * 패턴의 모든 URL에 대한 요청이 DispatcherServlet으로 전달된 후 urlMapping 정보에 의해 remotingProductService가 호출되어 HTTP Invoker 서비스가 제공된다.

    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/ProductService">remotingProductService</prop>
            </props>
        </property>
    </bean>

5.2.Client Configuration

클라이언트는 Spring에서 제공하는 org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean 클래스를 사용하여 HTTP Invoker Service에 접근할 수 있다.

Property NameDescriptionRequiredDefault Value
serviceUrlHTTP Invoker 서비스 접근 URL 정보이다. "http://" + 서버ip + ":" + port 번호 + "/" + 서비스 명 (ex.http://localhost:9002/ProductService)YN/A
serviceInterfaceHTTP Invoker 서비스로 노출되는 서비스의 인터페이스 클래스를 패키지정보와 함께 작성한다.YN/A

5.2.1.Samples

다음은 HTTP Invoker 클라이언트 속성 설정에 대한 예제이다. 클라이언트는 HttpInvokerProxyFactoryBean에서 property 설정 정보를 참조하여 HTTP Invoker 서비스에 접근하고 있다.

  • Configuration

    다음은 HTTP Invoker 서비스에 접근하는 HttpInvokerProxyFactoryBean의 속성을 정의한 context-remoting.xml 의 일부이다.

    <bean id="productServiceClient"
        class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
        <property name="serviceUrl"
            value="http://localhost:8080/anyframe.sample.remoting/remoting/ProductService" />
        <property name="serviceInterface"
            value="anyframe.sample.remoting.sales.service.ProductService" />
    </bean>

    Hessian/Burlap 서비스에 접근하는 클라이언트와 마찬가지로 serviceInterface Property에는 서비스가 구현하는 인터페이스 클래스를 설정하고. serviceUrl Property에는 서비스 URL을 작성하는데 HTTP Invoker라는 이름에서도 알 수 있듯이 HTTP 기반으로 제공되므로 HTTP URL을 작성하도록 한다. HTTP 방식으로 원격 서비스를 호출할 때 HTTP 클라이언트를 선택할 수 있다. 기본적으로 HttpInvokerProxyFactoryBean은 J2SE HTTP 클라이언트를 사용하지만, httpInvokerRequestExecutor 프라퍼티를 셋팅하여 Apache Commons HttpClient를 사용할 수도 있다.

    <!-- Add HTTP Invoker Client -->
    <bean id="productServiceClient" 
            class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
        <property name="serviceUrl" value="http://localhost:8080/ProductService" />
        <property name="serviceInterface" 
                value="anyframe.sample.remoting.sales.ProductService"/>
        <property name="httpInvokerRequestExecutor" ref="httpClient"/>    
    </bean>
    
    <bean id="httpClient" 
          class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"> 
        <property name="httpClient"> 
            <bean class="org.apache.commons.httpclient.HttpClient"> 
                <property name="connectionTimeout" value="2000"/> 
            </bean> 
        </property> 
    </bean>

  • Test Case

    다음은 앞서 정의한 속성 설정 파일들을 기반으로 하여 HTTP Invoker 서비스에 접근하는 예제인 ProductController.java 코드의 일부이다.

    public class HttpInvokerSpringSupportTest extends RemotingSpringTestCase {
    
    @Controller
    public class ProductController {
        @Resource(name = "productServiceClient")
        private ProductService productService;
    
        /**
         * get a product detail.
         * 
         * @param request
         * @param response
         * @return
         * @throws Exception
         */
        @RequestMapping("/remotingGetProduct.do")
        public ModelAndView get(HttpServletRequest request) throws Exception {
    
            String prodNo = request.getParameter("prodNo");
    
            if (!StringUtils.isBlank(prodNo)) {
                Product gettedProduct = (Product) productService.get(prodNo);
    
                gettedProduct.setImageFile("/upload/"
                        + gettedProduct.getImageFile());
                request.setAttribute("product", gettedProduct);
            }
    
            return new ModelAndView(
                    "/WEB-INF/jsp/remoting/sales/product/viewProduct.jsp");
        }
    
        /**
         * display product list
         * 
         * @param request
         * @param response
         * @return
         * @throws Exception
         */
        @RequestMapping("/remotingListProduct.do")
        public ModelAndView list(HttpServletRequest request,
                ProductSearchVO searchVO) throws Exception {
    
            String pageParam = (new ParamEncoder("productList")
                    .encodeParameterName(TableTagParameters.PARAMETER_PAGE));
            String pageParamValue = request.getParameter(pageParam);
            int pageIndex = StringUtil.isNotEmpty(pageParamValue) ? (Integer
                    .parseInt(pageParamValue)) : 1;
            searchVO.setPageIndex(pageIndex);
    
            Page resultPage = productService.getPagingList(searchVO);
    
            request.setAttribute("search", searchVO);
            request.setAttribute("productList", resultPage.getList());
            request.setAttribute("size", resultPage.getTotalCount());
            request.setAttribute("pagesize", resultPage.getPagesize());
            request.setAttribute("pageunit", resultPage.getPageunit());
    
            return new ModelAndView(
                    "/WEB-INF/jsp/remoting/sales/product/listProduct.jsp");
        }
    }


출처 - http://dev.anyframejava.org/docs/anyframe/plugin/remoting/4.5.2/reference/html/ch05.html



Posted by linuxism
,