[스프링MVC] 서비스 RPC화 이야기 - Deprecated된 HTTP Invoker

웹 개발/스프링 프레임워크

2021. 12. 14.

HttpInvoker는 스프링 5.3에서 Deprecated된 기술입니다.

 

HttpInvoker는 스프링 웹 애플리케이션에서 서비스를 손쉽게 HTTP 상에 노출하여 다른 앱에서 접근할 수 있도록 하는 기능이다.
스프링 웹 서비스와 스프링 클라이언트 사이에서 활용하기 적합한 기술이고 일종의 RPC로 동작한다.
클라이언트 측 코드는 그저 서비스 객체의 인터페이스를 호출하는 것이지만, 사실은 원격에 자리한 서비스를 호출하게 된다.

코드

의존성

목적 의존성
영속성 서비스 JPA2
영속성 서비스 공급자 Hibernate
임베디드 데이터베이스 H2
Repository 추상화 스프링 데이터 JPA
웹 애플리케이션 구성 스프링 MVC

HTTP 인보커로 원격 서비스 노출

HTTP 인보커를 활용하여 서비스를 노출하는 4단계를 살펴본다.

1) 웹 애플리케이션 컨텍스트 구성

HTTP 인보커로 앱 서비스를 HTTP 서비스로 노출할 것이므로 웹 애플리케이션 컨텍스트 구성이 미리 필요하다. 스프링 부트가 아닌 스프링 MVC를 사용하여 웹 앱을 구성한다고 가정한다.
따라서 WebMvcConfigurer를 구현하는 WebConfig 클래스를 작성하자.

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {}

서블릿 설정, 서블릿 매핑, 필터, 루트 컨텍스트 구성 등을 선언하는 web.xml이 필요하나, xml 작성 없이 프로그래밍으로 대체할 수 있다. AbstractAnnotationConfigDispatcherServeletInitializer를 상속한 WebInitializer 클래스를 작성하고 관련 메서드를 오버라이딩 한다.

public class WebInitializer2 extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] {
                DataServiceConfig.class
        };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] {
                HttpInvokerConfig.class, WebConfig.class
        };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {
                "/invoker/*"
        };
    }
}

2) HttpInvokerServiceExporter 빈과 서비스 노출

이 빈을 WebConfig 클래스에 함께 구성해도 무방하지만, 웹 앱 인프라와 커스텀 서비스 빈은 분리하여 구성하는 것이 좋다. 그러니 HttpInvokerConfig 클래스에서
HttpInvokerServiceExporter 빈을 등록하자. 이 빈은 SingerService 의 메서드를 HTTP로 원격 호출할 수 있도록 노출한다.

@Configuration
public class HttpInvokerConfig {

    @Autowired
    SingerService singerService;

    @Bean(name = "/httpInvoker/singerService")
    public HttpInvokerServiceExporter httpInvokerServiceExporter() {
        HttpInvokerServiceExporter invokerService = new HttpInvokerServiceExporter();
        invokerService.setService(singerService);
        invokerService.setServiceInterface(SingerService.class);
        return invokerService;
    }
}

HttpInvokerServiceExporter 빈은 노출하려는 서비스의 인터페이스와 구현체를 요구한다. 빈의 이름이 원격 서비스의 URL 매핑에 영향을 주는 점을 기억하자.

서비스 프록시를 통한 원격 호출

3) 서비스 프록시 생성과 테스트 코드 작성

테스트 코드를 만들어 원격 노출된 서비스가 잘 동작하는지 테스트할 것이다.

앞 서 1, 2단계에서 서비스 노출 설정은 이미 완료됐다. 원격의 SingerService는 HTTP 주소http://localhost:8080/remoting/invoker/httpInvoker/singerService 로 노출되는 상태이다.

클라이언트는 원격 서비스를 클래스의 메서드를 그냥 호출하는 느낌으로 사용할 수 있다. (RPC)

@ContextConfiguration(classes = RmiClientConfig.class)
@RunWith(SpringRunner.class)
public class RmiTests {
    private Logger logger = LoggerFactory.getLogger(RmiTests.class);

    @Autowired
    private SingerService singerService;

    @Test
    public void testRmiAll() {
        List<Singer> singers = singerService.findAll();
        assertEquals(3, singers.size());
        listSingers(singers);
    }

    @Test
    public void testRmiJohn() {
        List<Singer> singers = singerService.findByFirstName("John");
        assertEquals(2, singers.size());
        listSingers(singers);
    }

    private void listSingers(List<Singer> singers){
        singers.forEach(s -> logger.info(s.toString()));
    }
}

테스트 컨텍스트를 구성하는 RmiClientConfig 클래스는 아래와 같다. HttpInvoerProxyFactoryBean에게 SingerService 프록시 빈을 생성을 요청한다. 따라서 클라이언트는 HTTP 인보커 기저에 깔려있는 프로토콜에 관심을 두지 않아도, 그냥 프록시의 메서드를 호출하는 걸로 원격 서비스를 이용하게 된다.

@Configuration
public class RmiClientConfig {

    @Bean
    public SingerService singerService() {
        HttpInvokerProxyFactoryBean factoryBean = new HttpInvokerProxyFactoryBean();
        factoryBean.setServiceInterface(SingerService.class);
        factoryBean.setServiceUrl("http://localhost:8080/remoting/invoker/httpInvoker/singerService");
        factoryBean.afterPropertiesSet();
        return (SingerService) factoryBean.getObject();
    }
}

배포 및 테스트

4) 웹 서비스 배포하기

여태 구성한 서블릿을 톰캣에 배포하여야 한다. WAR 파일 배포에 관한 연관 글 참고가 필요하다. WAR 빌드 절차는 예제 프로젝트의build.gradle에 정의되어 있으므로 remoting.war 를 바로 빌드할 수 있다.

톰캣에 배포 후 localhost 접속시 아래처럼 index.html 내용이 표시되어야 한다.
|

image

|
|:--:|
| http://localhost:8080/remoting 접속 정상 화면|

톰캣 배포가 정상적임을 확인했으면, 3단계에서 작성한 테스트 코드를 IDE에서 실행하면 된다.

image

요약

  1. 웹 애플리케이션을 구성한다.
  2. 서비스를 HttpInvokerServiceExporter를 사용해 노출한다. 빈의 이름으로 원격 서비스의 URL 매핑을 설정할 수 있다.
  3. 원격 서비스의 HTTP 주소를 HttpInvokerProxyFactoryBean에 바인딩하면, 해당 서비스를 호출하는 프록시 빈을 얻을 수 있다. 이 빈으로 원격 서비스 접근이 메서드 호출 수준으로 추상화된다.
  4. WAR 파일을 빌드하여 톰캣에 배포 후 테스트를 진행하면 된다.