Enterprise Design pattern

Byung Seon Kang·2022년 10월 11일
0

서블릿에 대해

목록 보기
9/9

MVC패턴, 그리고 Front Controller 패턴등에 대해 알아보자

  • 이 글은 Head First Servlet & JSP를 기반으로 작성되었습니다.

Web app이 복잡해지면서..

  • 트래픽이 많은 거대한 웹사이트는 복잡한 하드웨어 아키텍쳐를 가지고 있다.
    • software와 data가 여러 대의 하드웨어에 분산되어 있음.
  • Scale up만으로는 한계가 있어 Scale out을 사용해서 throughput을 증가시키기 시작함.
  • non-functional requirement도 만족시켜야 했음.
    • performance
    • modularity
    • flexibility
    • maintainability
    • extensibility
      등등
  • 아키텍쳐가 필요해짐.

MVC

  • Model Controller View 분리.
    • cohesion 증가
    • loosely coupled
    • 그밖에 maintainablity 등등 다양한 장점.
  • 그런데 이 각 요소들을 한 서버에 놓는 것이 아니라 remote, 즉 각각 서버를 나눠서 놓게 된다면 어떻게 통신해야할까?

JNDI and RMI

  • 해결책은 위 두가지
  • 기존 Java와 J2EE는 네트워크 상에서 통신하며 주고받아야 하는 object가 생겼을 때 몇가지 문제점이 생긴다.
    • locating remote object
    • local object와 remote object의 간의 low level network/IO communication
  • 요걸 도와주는게 JNDI와 RMI 두 친구들

JNDI 간단 설명.

출처: 오라클 공식문서

  • Stands for Java Naming and Directory Interface
  • 이름 지정 및 directory service 접근하는 API를 말함.
  • 뭔가를 찾을 때 사용하는 중앙화된 네트워크를 제공한다.
    • object를 JNDI에 등록하고나면 다른 프로그램이 나의 object를 사용하고 싶을 때 JNDI를 통해 찾는다.
  • JNDI는 네트워크 상의 component 재배치를 쉽게 만들어준다.
    • component를 재배치하고 나면, JNDI에게 새로운 위치를 말해주기만 하면 된다.
  • 이러면 client component든 오직 JNDI를 어떻게 찾을지만 알면 되고, JNDI에 등록된 object의 실제 위치를 알 필요가 없음!

RMI

  • Stands for Remote Method Invocation
  • 네트워크상에서 통신하기 위해 object를 얻는 과정을 매우 간단하게 만들어준다.
    • remote object 상에 존재하는 method를 실행하기 위해 그 object를 가져오는 것을 쉽게 만들어준다는 의미.
    • remote object를 local object처럼 사용하게 해준다.
    • 음.. low level network/IO Communication 도와주는애가 얘인가?

RMI는 어떻게 이를 수행하나

  • proxy를 생성하고 registry에 object를 등록한다.

  • 서버의 method를 사용하길 원하는 client는 이 registry를 훑어보고 remote proxy의 복사본을 가져온다.

  • 이후 remote proxy(client 상에 존재하는 복사본)를 사용해서 local object인 것 처럼 method를 사용한다.

    • 이 remote proxy를 stub이라고 함.
    • gRPC에서도 동일하게 사용했던 것으로 기억

    역할

    • socket
    • I/O stream
    • TCP/IP
    • serialize/deserialize method argument
    • return value
    • handling exception 등등.

참고

  • 서버단에도 proxy가 보통 있음.
    • skeleton이라고 불림.
    • 비슷한 작업 수행.

좀 더 자세하게

  1. remote interface 생성(getCustData()와 같은 메소드들이 있음)
    stub과 실제 model service가 이 인터페이스에서 구현됨.
  2. remote implementation 생성.
    model 서버에 존재하는 실제 모델 object를 만든다는 의미
    model을 registry service(JNDI, RMI)에 등록하는 코드도 포함되어 있다
  3. stub과 skeleton(쓰면)을 생성.
    RMI는 rmic라 불리는 컴파일러를 제공하는데 이는 proxy 생성해주는 컴파일러임.
  4. model 서비스 실행.
    registry에 등록하고 클라이언트의 요청 기다릴 것.

간단하게 pseudo code로 비교해보기

RMI 없이 하면

public void goClient() {
	try {
    	//새로운 소켓 생성
        
        //outputstream 가져옴
        //ObjectOutputStream에 연결
        
        //opcode와 op argument 전송
        //OS flush
        
        //InputStream 획득
        //ObjectInputStream에 연결
        
        //return value 읽음
        //exception 처리
        
        //close
       
    }//remote exception catch하고 처리하는 부분
}

RMI 사용시

RMI 사용하면
public void goClient(){
	try {
    	//remote object(stub) 찾기
        
        //remote object의 method 호출
        
       
    }//remote exception 처리
}

RMI와 JNDI controller에 추가


현재 controller와 model 다른서버에 분할한 상태

  1. model component를 JDNI service에 등록
  2. controller에서 요청을 받고 controller는 JNDI를 탐색해서 stub proxy get.
  3. controller는 stub(model에서 가져온 복제품)에서 비즈니스 method call을 사용.

문제점

위 상황에는 문제가 존재한다.

  • 컨트롤러에서 다음과같은 작업들을 모두 수행하고 있음.
    • JNDI lookup
    • stub써서 remote method call.
  • 너무 controller에 강결합되어있음

해결방안

  1. Business Delegate 사용

    pesudo code
//get the request and do a JNDI lookup
//get back a stub

//call to the business method
//handle & abstract any remote exceptions
//send the return value to the controller
  • 자 근데 여기서도 문제가 있다.
    • service를 탐색하는 코드(JNDI lookup)이 중복됨.
    • 이걸 어떻게 해결할까
  1. service locator 사용

    pseudo code
// obtain an InitialContext object
// perform remote lookup
// handle remote issues
//optionally, cache references
  • JNDI look up 및 stub 가져오는 작업을 하나의 service locator에서 해주는 것.

View까지.

  • JSP까지 쓴다고 하자.
    • JSP에서도 그럼 stub을 사용한다.
    • 근데 그 가져온 stub이 갱신이 안되어있는녀석이라면?
  • 문제 생김.
    • 거의 갱신이 안될 녀석이면 상관 없음
    • 하지만 실시간 갱신이 계속 되는녀석이면 갱신이 되더라도 stub에서는 이를 인식할 수 없기 때문에 문제가 생긴다.

Controller에 대한 고찰

  • MVC controller의 작업 봐보자
	public class ControllerServlet extends HttpServlet {
    	public void doPost(request, response) {
        //1 : request parameter 처리
     		String c = req.getParameter("startDate");
            
            // date parameter에서 data conversion
            
            //date가 범위 내에 있는지 validate
            
            //validation중 error 발생 시 처리
            
        //2. model 처리
        	//model component 불러오기
            
            //model result를 request object에 추가
            //필요하면 bean 참조
            
        //3. view 처리
        	//view JSP에 dispatch
            
        }
    }
  • model, view component와 너무 결합되어 있음.
  • 또한 중복되는 코드가 많다.
  • 개선해보자
public class ControllerServlet extends HttpServlet {
    	public void doPost(request, response) {
        	//validation component 호출
            
            //request processing 호출
            
            //dispatch JSP
            
        }
}

Front Controller

  • Front controller pattern을 사용한다면 서블릿 여러개가 필요 없다!
  • Spring에서 dispatcher servlet도 이와 동일한 패턴을 사용하는 것이라 보면 됨
    • 가장 앞단에서 요청 받고, rest Controller에 이를 전달해줌.
      관련 좋은 글
profile
왜 필요한지 질문하기

0개의 댓글