• 티스토리 홈
  • 프로필사진
    아몬드맛빼빼로
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
  • 반응형
아몬드맛빼빼로
  • 프로필사진
    아몬드맛빼빼로
    • 분류 전체보기 (70)
      • Java (13)
      • C (3)
      • Spring (8)
      • Kotlin (2)
      • 회고 (7)
      • Backend (19)
      • 기타 (9)
      • DevOps (4)
      • Network (3)
      • CS (2)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
# Home
# 공지사항
#
# 태그
# 검색결과
# 방명록
  • [Java] Java RMI
    2025년 10월 06일
    • 아몬드맛빼빼로
    • 작성자
    • 2025.10.06.:29

    이게 뭐야

    여느 때와 같이 IntelliJ IDEA로 Spring Boot 애플리케이션을 개발하던 중 눈에 띈 한 가지 로그가 있었다.

    INFO  2025-10-06 01:15:59,638 [RMI TCP Connection(1)-127.0.0.1] [DirectJDKLog :: log :: 168] - Initializing Spring DispatcherServlet 'dispatcherServlet'
    INFO  2025-10-06 01:15:59,638 [RMI TCP Connection(1)-127.0.0.1] [FrameworkServlet :: initServletBean :: 532] - Initializing Servlet 'dispatcherServlet'
    INFO  2025-10-06 01:15:59,639 [RMI TCP Connection(1)-127.0.0.1] [FrameworkServlet :: initServletBean :: 554] - Completed initialization in 1 ms

    RMI TCP Connection? TCP Connection 까지는 알겠는데 RMI라는 키워드를 처음 듣게 되어서 이에 대해 공부하게 되었다. 결론부터 말하자면 IntelliJ IDEA가 Tomcat과 Spring Boot 애플리케이션을 원격으로 구동하면서 Java RMI를 사용한 것이다.

    RMI?

    분산되어 존재하는 객체 간의 메세지 전송을 목적으로 하는 것으로 COBRA, DCOM 등의 프로토콜들을 총칭하는 단어이다. 여러 프로그램들이 1대의 PC에 구성되어 있더라도 메모리 Heap 영역을 공유하지는 않기 때문에 서로의 메서드를 호출하고 사용할 수는 없다. 이를 가능케 하는 것이 RMI 프로토콜들이며 Java에서는 이를 사용하는 것을 높은 추상화 수준으로 제공한다.

    더보기

    COBRA? DCOM?

     

    COBRA는 객체 관리 그룹(Object Management Group; OMG)이 제정한 프로토콜로 분산 객체간의 통신을 처리하는 기능을 규정한다. Windows 95, Mac OS 7, UNIX 등의 운영체제에 채택되었다.

     

    DCOM은 네트워크 상에서 클라이언트 역할의 프로그램이 다른 컴퓨터의 서버 역할을 하는 프로그램에 무언갈 요청할 수 있도록 하는 마이크로스프트가 규정한 인터페이스로 Windows 95와 Windows NT 운영체제에 탑재되었다. RPC 프로토콜 기반으로 국제 표준으로 시작되지는 않았지만 UNIX와 IBM의 메인프레임 등에도 탑재되며 TCP/IP 기반 HTTP 프로토콜을 사용할 수도 있다.

    Java RMI

    Java에서 제공하는 RMI를 사용하면 한 시스템의 Java 프로그램이 다른 Java 프로그램의 메서드를 호출할 수 있다. 이때 클라이언트 측의 Stub 객체와 서버 측의 Skeleton 객체가 통신을 중계한다.

    더보기

    Stub, Skeleton

     

    정확히는 현대 Java에선 동적 프락시 객체가 중계한다! Stub, Skeleton 객체는 과거 Java RMI가 처음 출시되었을 때의 명세이다.

    RMI 통신을 직접 구현한다면 Socket 단위부터 시작하기에 C언어로 이를 구현하는 것과 마찬가지가 돼버리지만 Java RMI는 이러한 하위 계층의 구현을 추상화하여 상대적으로 구현하기 쉽게 해 준다.

    Java RMI 구현해 보기

    예제코드와 함께 설명해 보겠다.

    import java.rmi.Remote;
    import java.rmi.RemoteException;
    
    public interface Calculator extends Remote {
        int add(int a, int b) throws RemoteException;
    }

    RMI 인터페이스를 우선 선언해야 한다. 서버와 클라이언트가 메서드를 공유하기 위해서는 인터페이스를 통하여 공유되어야 하며 이때 java.rmi.Remote를 확장해야 한다. 원격 접속을 위하여 반드시 public으로 선언하여야 하며 RemoteException을 던질 수 있음을 명시해야 한다.

     

    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    import java.rmi.server.UnicastRemoteObject;
    
    public class CalculatorImpl extends UnicastRemoteObject implements Calculator {
        protected CalculatorImpl() throws RemoteException {
            super();
        }
        
        public int add(int a, int b) throws RemoteException {
            return a + b;
        }
        
        public static void main(String[] args) {
            try {
                Calculator calculator = new CalculatorImpl();
                Registry registry = LocateRegistry.createRegistry(1099);
                registry.bind("Calculator", calculator);
                System.out.println("Server ready");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    RMI 서버의 중심이 될 클래스를 정희 하며 다양한 구현 방법이 있지만 UnicastRemoteObject를 상속받아 구현하는 것이 가장 빠르고 쉬운 방법이다. 이를 상속할 시 하위 계층을 추상화하여 통신을 쉽게 구현할 수 있도록 해주며 구현한 메서드를 레지스트리에 등록해 준다.

     

    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    
    public class Client {
        public static void main(String[] args) {
            try {
                Registry registry = LocateRegistry.getRegistry("localhost", 1099);
                Calculator calculator = (Calculator) registry.lookup("Calculator");
                int result = calculator.add(5, 3);
                System.out.println("Result: " + result);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    클라이언트 측의 사용은 비교적 간단한 편이다. 호스트와 포트를 기입하고 원하는 클래스를 찾은 후 메서드를 호출하면 된다.

    다른 기술들과 비교

    • vs REST API - REST API는 플랫폼에 독립적이며 어떤 언어를 사용하든지 HTTP 클라이언트만 있으면 사용가능 하다. 방화벽을 사용하는 것에도 친화적으로 HTTP/HTTPS 포트를 사용하고 캐싱/로드밸런싱 등의 인프라 활용 역시 간편하다. 그러나 직렬화/역직렬화 과정의 오버헤드가 큰 편이고 타입 안정성이 떨어져 런타임 오류가 사실상 강제적이다.
    • vs gRPC - Protocol Buffers를 사용한 바이너리 직렬화로 매우 빠르고 다양한 언어를 지원한다. 실시간 통신에 매우 강력하고 타입 안정성이 매우 뛰어난 편이다. 사실상 학습 곡선과 같은 부분이 아니라면 Java RMI의 대체제이다.
    • vs SOAP - XML 기반의 엄격한 규칙을 사용하는 프로토콜로 트랜잭션과 프로토콜 단위에서 규정된 보안 기능이 강력한 편이지만 설정이 복잡하고 XML 직렬화/역직렬화 과정이 치명적으로 오버헤드가 발생한다.
    • vs MQ - 비동기 통신으로 느슨한 결합을 추구하며 부하 분산과 안정성이 높다. 그러나 동기 방식의 통신에는 부적합하고 인프라 구축 비용이 존재한다.
    • vs GraphQL - 클라이언트가 필요한 데이터만 명확히 요청할 수 있으며 타입 안정성이 우수하다. 그러나 기술 자체의 방향성이 다르며 RMI는 범용 원격 메서드 호출이 주목적이지만 GraphQL은 데이터 조회에 특화되어 있다.
    • vs Web Socket - 양방향 실시간 통신에 최적화되어 있으며 지연시간이 적은 편이다. 그러나 연결 유지로 인한 오버헤드가 있고 RMI의 목적과는 방향성이 다르다.

    결론

    Java RMI는 여전히 극히 일부 분야에선 유용할 수 있다. 로컬 시스템 내부에서 같은 Java 프로그램을 호출할 때 추가 기술의 도입 없이 적은 성능 비용으로 사용할 수 있는 통신 규약이라는 것만으로도 충분한 가치가 있다. 그러나 현대 대규모 서비스에서는 부적합하다. gRPC와 같은 마이크로서비스에 특화된 기술이 있고 REST API나 GraphQL, Web Socket 같은 통신 규약이 이미 완전하게 자리 잡았기에 입지가 좁아진 상태인 것도 맞다. 서버 개발자로서 해당 기술을 사용할 일이 있을지는 모르겠지만 Java 개발을 할 때 한 가지 기술적 선택지를 얻게 된 것이니 한번 알아보는 것도 나쁘지는 않은 것 같다.

    반응형
    저작자표시 비영리 변경금지 (새창열림)

    'Java' 카테고리의 다른 글

    [Java] Gradle 9.0  (0) 2025.12.03
    [Java] WAR vs JAR  (0) 2025.12.01
    [Java] Jitpack  (0) 2025.08.30
    [Java] JavaDoc  (0) 2025.05.05
    [Java] StableValue!  (0) 2025.04.07
    다음글
    다음 글이 없습니다.
    이전글
    이전 글이 없습니다.
    댓글
조회된 결과가 없습니다.
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
목차
표시할 목차가 없습니다.
    • 안녕하세요
    • 감사해요
    • 잘있어요

    티스토리툴바