책너두 (헤드 퍼스트 디자인 패턴) 36일차 (~488p)
- Book/헤드 퍼스트 디자인 패턴
- 2023. 8. 15.
요약
- 프록시 패턴
- 서버에 필요한 코드 살펴보기
- 작동 방식
- 클라이언트 코드 살펴보기
- GumballMachine 클래스를 원격 서비스로 바꾸기
- RMI 레지스트리 등록하기
- GumballMonitor 클라이언트 코드 고치기
- 서버에 필요한 코드 살펴보기
메모
서버에 필요한 코드 살펴보기
[원격 인터페이스]
import java.rmi.*;
public interface MyRemote extends Remote {
public String sayHello() throws RemoteExceptionl;
}
[원격 서비스를 구현한 클래스]
import java.rmi.*;
import java.rmi.server.*;
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
private static final long serialVersionUID = 1L;
public String sayHello() {
return "Server says, 'Hey'";
}
public MyRemoteImpl() throws RemoteException { }
public static void main (String[] args) {
try {
MyRemote service = new MyRemoteImpl();
Naming.rebind("RemoteHello", service);
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
- 원격 객체를 만드는 가장 쉬운 방법은 UnicastRemoteObject 확장하기 임.
- 원격 인터페이스를 반드시 구현해야 함.
- 원격 객체의 인스턴스를 만들고, Naming.rebind() 정적 메소드를 써서 rmiregistry에 결합함.
- 클라이언트에서 RMI 레지스트리로 서비스를 검색할 때는 여기에서 지정한 이름을 사용함.
- 클라이언트는 스텁 객체(프록시)를 가져와야 함.
- 이때 RMI 레지스트리가 활약함.
- 클라이언트는 룩업(lookup)으로 스텁 객체를 요청함.
- 이름을 건네주면, 그 이름에 맞는 스텁 객체를 요구함.
MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/RemoteHello");
- 클라이언트는 항상 서비스를 원격 인터페이스 형식으로 지정함.
- 원격 서비스를 구현한 클래스의 이름은 전혀 몰라도 됨.
- lookup()은 Naming 클래스에 들어있는 정적 메소드임.
- 서비스를 등록할 때 사용한 이름을 적어줘야 함.
- 서비스가 돌아가고 있는 시스젬의 호스트 이름 or IP주소를 함께 적어야 함.
- 리턴된 스텁은 인터페이스 형식으로 캐스팅해야 함. → lookup() 메소드는 항상 Object 형식의 객체를 리턴하기 때문.
작동 방식
1. 클라이언트에서 RMI 레지스트리를 룩업함.
Naming.lookup("rmi://127.0.0.1/RemoteHello");
2. RMI 레지스트리에서 스텁 객체를 리턴함.
- 스텁 객체는 lookup() 메소드의 리턴 값으로 전달됨.
- RMI에서는 그 스텁을 자동으로 역직렬화함.
- 이때, rmic에서 생성해준 스텁 클래스는 반드시 클라이언트에만 있어야 함.
- 이 클래스가 없으면 역직렬화 할 수 없음.
3. 클라이언트는 스텁의 메소드를 호출함.
- 스텁이 진짜 서비스 객체라고 생각함.
클라이언트 코드 살펴보기
import java.rmi.*;
public class MyRemoteClient {
public static void main(String[] args) {
new MyRemoteClient().go();
}
public void go() {
try {
MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/RemoteHello");
String s = service.sayHello();
System.out.println(s);
} catch(Exception ex) {
ex.printStackeTrace();
}
}
}
- RMI 레지스트리 룩업을 처리하는 Naming 클래스가 java.rmi 패키지에 들어있음.
- service.sayHello()와 같이 그냥 보통 메소드를 호출할 때와 똑같은 식으로 호출하면 됨.
- RemoteException이 발생할 것에 대비하기만 하면 됨.
GumballMachine 클래스를 원격 서비스로 바꾸기
1. GumballMachine의 원격 인터페이스를 만듦.
import java.rmi.*;
public interface GumballMachineRemote extends Remote {
public int getCount() throws RemoteException;
public String getLocation() throws RemoteException;
public State getState() throws RemoteException;
}
- 모든 리턴 형식은 원시 형식 또는 Serializable 이어야 함.
- 지원해야 하는 메소드 모두 RemoteException을 던질 수 있음.
2. 인터페이스의 모든 리턴 형식을 직렬화할 수 있는지 확인해야 함.
- State 클래스는 직렬화할 수 없는 리턴 형식이므로 고쳐야 함.
import java.io.*;
public interface State extends Serializable {
public void inserQuater();
...
}
- 여기서, 모든 State 객체에는 뽑기 기계의 메소드를 호출하거나 상태를 변경할 때 사용하는 뽑기 기계 레퍼런스가 들어 있음.
- State 객체가 전송될 때, GumballMachine 클래스도 전부 직렬화해서 같이 보내는 일은 바람직하지 않음.
- 다음과 같이 간단하게 수정하자.
public class NoQuaterState implements State {
private static final long serialVersionUID = 2L;
transient GumballMachine gumballMachine;
// 기타 메소드
}
- transient 키워드를 쓰면, JVM에서 그 필드를 직렬화하지 않음.
- 하지만, 객체를 직렬화해서 전송받은 후에 이 필드를 호출하면 안 좋은 일이 발생할 수 있다는 사실을 기억해야 함.
- 이제 GumballMachine 클래스를 네트워크로 들어온 요청응ㄹ 처리하는 서비스로 고쳐야 함.
import java.rmi.*;
import java.rmi.server.*;
public class GumballMachine extends UnicaseRemoteObject implements GumballMachineRemote {
private static final long serialVersionUID = 2L;
// 기타 인스턴스 변수
public GumballMachine(String location, int numberGumballs) throws RemoteException {
// 생성자 코드
}
public int getCount() {
return count;
}
public State getState() {
return state;
}
public String getLocation() {
return location;
}
// 기타 메소드
}
- GumballMachine 클래스를 UnicastRemoteObject 서브클래스로 만들어야 원격 서비스 역할을 할 수 있음.
RMI 레지스트리 등록하기
- 서비스 요청을 받아서 처리하도록 시동을 거는 일만 남음.
- p482 참고
GumballMonitor 클라이언트 코드 고치기
- 네트워크로 데이터를 받아오기로 계획을 세움.
- p483 참고
📍 프록시에 있는 메소드를 호출하면 네트워크로 메소드 호출이 전달됨. 호출 결과로 String, 정수, State 객체가 리턴됨. 프록시를 사용하므로 GumballMonitor는 원격 호출을 하고 있다는 사실을 몰라도 됨. 물론 RemoteException을 대비해야 함.
'Book > 헤드 퍼스트 디자인 패턴' 카테고리의 다른 글
책너두 (헤드 퍼스트 디자인 패턴) 38일차 (~513p) (0) | 2023.08.17 |
---|---|
책너두 (헤드 퍼스트 디자인 패턴) 37일차 (~502p) (0) | 2023.08.16 |
책너두 (헤드 퍼스트 디자인 패턴) 35일차 (~474p) (0) | 2023.08.14 |
책너두 (헤드 퍼스트 디자인 패턴) 34일차 (~463p) (0) | 2023.08.12 |
책너두 (헤드 퍼스트 디자인 패턴) 33일차 (~452p) (0) | 2023.08.11 |