본문 바로가기

Java

[Java] RMI

 

RMI란?

- 원격 메서드 호출이란 로컬 컴퓨터에서 원격 컴퓨터의 메서드를 호출하는 기술이다.

실제 클라이언트에서 원격 컴퓨터에 존재하는 메서드를 호출할 것이고, 클라이언트가 원격 메서드를 호출 했을때 원격 컴퓨터의 CPU를 사용하며, 클라이언트는 그 결과값만을 네트웍으로 전송받는다.


RMI의 데이터 전달 기법은?

-매개변수와 반환값이 없는 메서드의 호출은 의미가 없습니다. 로컬 머신에서 원격으로 메서드를 호출하더라도 매개변수를 RMI 통신을 통해서 날려주고, 그리고 리턴값을 다시 되돌려 받아야 합니다. 이것을 해결하기 위해서 RMI 내부에서는 객체 직렬화(Serialization)의 기법을 이용합니다. 매개변수로 넘겨 줄 객체를 직렬화한 후 메서드를 호출할 때 함께 보내주는 것입니다. 그리고 그 결과값 또한 직렬화되어 원격 컴퓨터로부터 반환됩니다.


RMI모델

- RMI를 구축하기 위해서는 원격지의 컴퓨터에 RMI Server가 필요하다. 이 RMI Server에 객체를 넣어두고 (바인딩) 로컬 머신에서 접근한 후 객체의 메서드를 호출하는 것이다. 기본적으로 RMI Registry라는 서버모델이 제공 되기는 하나 이것은 단순 개발용이고, 일반적으로 RMI기반의 모델 중 가장 널리 알려진 것이 바로 EJB를 서비스해주는 J2EE모델이다. J2EE기술은 비지니스 로직을 처리하기 위한 RMI 기반의 응용 모델이며, 여기서 서비스 되는 객체를 EJB라고 한다.


▣ RMI Registry
◈ 자바 RMI는 원격 객체를 관리하고 서비스하는 원격 객체 컨테이너(Container)를 제공하는데, 이것을 RMI Registry라고 한다.

▣ 바인딩(Binding)
◈ RMI Registry에 원격 객체를 등록하는 과정을 바인딩(Binding)이라고 한다.
◈ RMI Registry에 원격 객체를 등록할 때에는 객체를 식별할 수 있는 식별자(Name)와 함께 등록해야 한다.

- J2EE상업 모델 중 가낭 잘 알려진 것이 웹로직이다.


클라이언트의 원격 참조 객체는 그냥 만들어지는 것이 아니고 클라이언트로부터 LookUp이라는 과정을 통해 서버로부터 내려받아야 한다. 이 룩업은 원격 객체의 바인딩 과정에서 사용한 식별자(Name)를 사용하여 RMI Registry에 존재하는 객체를 클라이언트 측에서 검색하는 작업이다. 그리고 클라이언트가 이 원격 객체를 LookUp하였을때 RMIRegistry는 원격객체를 대신 할 원격참조객체를 클라이언트에 보내주게 되며, 클라이언트는 이 원격참조객체를 통하여 원격객체를 호출 하는 것이다.



RMI만들기.

1.원격 인터페이스의 작성

-원격 인터페이스는 원격 객체가 사용 할 메서드를 명시하는 과정임.

▣ 원격 인터페이스
◈ public interface IHello extends Remote{
◈        public String sayHello(String name) throws RemoteException;
◈ }
- 여기에 명시된 메서드만이 원격으로 호출이 가능하다.

- 위의 이유로 이 인터페이스는 클라이언트측에 공개 되어야 한다.(수동으로...메일이든 뭐든..)

- Remote를 상속하며, RemoteException처리를 해주어야 한다.(규약)


2.원격 클래스 만들기

- 원격 인터페이스를 구현해야 한다.

- UnicastRemoteObject클래스를 상속해야 한다.

▣ 원격 클래스의 실제 구현
◈ public class HelloImpl extends UnicastRemoteObject implements IHello {
◈         public HelloImpl() throws RemoteException { }
◈         public String sayHello(String name) throws RemoteException{
◈             System.out.println(name + "님 안녕하십니까! ");
◈             return name + "님 안녕하십니까! ";
◈         }
◈ }

- 생성자에도 Exception처리가 있음을 주의

- 인터페이스인 IHello를 구현하고 있다.


3.Stub 클래스 만들기

- 클라이언트가 사용하는 원격 참조 객체를 만들기 위해서는 스텁(Stub)클래스가 필요하다.

- 이 스텁 클래스로 객체를 만들면 원격 참조 객체(가짜 객체)가 되는 것이다.

- 제공되는 rmic.exe라는 툴을 사용한다.

javac HelloImpl.java

rmic HelloImpl

▣ rmic.exe로 생성된 스텁(Stub)과 스켈레톤(Skeleton) 파일
◈ HelloImpl_Stub.class
◈ HelloImpl_Skeleton.class

-Java 1.2이후에서는 Stub클래스에 스켈레톤 클래스의 기능이 통합되어 있으며, 버젼 유지를 위해 현재도 스켈레톤 클래스는 같이 생성된다.


4.스텁과 스켈레톤을 사용하여 바인딩 시키기

- 스텁과 스켈레톤까지 작성했다면 원격 클래스를 이용하여 원격 객체를 만든 후 RMI Registry에 바인딩 시키는 서버 프로그램이 필요하다


▣ 바인딩을 위한 서버 프로그램의 구현
import java.rmi.*;
import java.rmi.server.*;
public class HelloRMIServer{
    public static void main(String[] args)    throws Exception {
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new RMISecurityManager());
        }
        HelloImpl h = new HelloImpl();
        Naming.rebind("rmi://203.252.134.119:1099/BABO", h);
        System.out.println("HelloImpl의 객체 h를 BABO이름으로 바인딩");    
    } //end of main
} //end of HelloRMIServer

▣ 자바 시스템 차원의 보안 정책 파일
◈ [JAVA_HOME]\jre\lib\security\java.policy
◈ 자바 설치 디렉토리의 jre 디렉토리를 확인하시기 바랍니다.


- 원격 클래스 HelloImpl의 객체 h를 만든 후, Naming의 rebind()를 이용해서 RMI Registry에 바인딩시키고 있다.

- 위의 HelloRMIServer를 실행시키면 RMI Registry에 원격객체가 등록된다.

(단, RMI Registry를 실행시킨 후 HelloRMIServer를 실행해야 한다.)


◈ java -Djava.security.policy=rmi.policy HelloRMIServer


start rmiregistry(포트 변경 할시 start rmiregistry 2000) - 디폴트 1099번

- 여기서 포트를 변경하려면 위의 rebind()메서드에서 사용한 포트도 변경해줘야 한다.

- 클라이언트가 원격객체를 Look Up할때 RMI서버는 원격 참조 객체(stub)의 메모리를 직렬화시켜 클라이언트로 전송한다.

- 이것을 역직렬화 하기 위해서는 원격 참조 객체의 클래스 파일이 필요한데 이것이 stub파일이다.

- 따라서 stub파일은 클라이언트가 다운로드 할 수 있는 곳에 위치 시켜야 하며, 이때 위치는 codebase를 사용하여 지정한다.


5.Look Up


▣ 클라이언트의 룩업과정을 순서
◈ Lookup 요청
◈ 직렬화된 Stub 객체 반환
◈ Stub 파일을 찾기 위해서 codebase 검색
◈ Stub 클래스 파일 요청
◈ Stub 클래스 파일 다운로드
◈ 직렬화된 Stub 객체와 Stub 클래스를 이용해서 역직렬화


- 역직렬화를 마치면 원격 참조 객체가 만들어지며, 이 원격참조객체를 이용해서 클라이언트는 메서드를 호출 할 수 있다. 단 실제 메서드를 호출하기 위해서는 원격참조객체를 인터페이스로 캐스팅 해주어야 한다. (그래서 공개되어야 하는 것이다..)


import java.rmi.*;
public class HelloRMIClient {
    public static void main(String[] args)    throws Exception {
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new RMISecurityManager());
        }
        IHello h = (IHello)Naming.lookup("rmi://203.252.134.119:1099/BABO");
        String str = h.sayHello("홍길동");
        System.out.println(str);
    } //end of main
} //end of HelloRMIClient class

- 원격 인터페이스로 사용 할 클래스 파일 확보

- 원격 클라이언트 프로그램 컴파일

javac HelloRMIClient.java

- 실행

java -Djava.security.policy=rmi.policy -Djava.rmi.server.codebase=http://www.jabook.org/java/rmi/ HelloRMIClient

- 위의 url은 스텁 파일이 있는 url


- 룩업을 과정을 거쳐서 원격 참조 객체를 얻었다면 객체가 로컬에 있는 것처럼 메서드를 호출할 수 있습니다. 메서드를 호출하기 위해서는 서버에서 배포하는 원격 인터페이스를 이용해서 원격 참조 객체를 캐스팅해야만 합니다. 위의 예에서는 룩업과 동시에 원격 인터페이스로 캐스팅하고 있습니다.

출처 : jabook.org