본문 바로가기

CS ﹒ Algorithm/DesignPatterns

디자인 패턴 (6) Adapter Pattern : 어댑터 패턴 (Spring HandlerAdapter 뜯어보기)

 

 

어댑터 패턴이란 ?

 

기존 코드를 클라이언트가 사용하는 인터페이스의 구현체로 바꿔주는 패턴이다.

오늘은 직접 만든 예제가 없다.

내가 연습용으로 작성한 것은 있지만, 실제 소스코드에 설명하기 좋은 쓸만한 예시들이 많기 때문이다.

그 중 자바의 BufferedReader - InputStreamReader - System과 스프링의 HandlerAdapter로 이 패턴을 설명하도록 하겠다.

 

위의 경우, BufferedReader에 System 클래스에서 제공하는 System.in을 이용해 값을 입력하고 싶지만 둘을 이어줄 방법이 없다.

따라서 InputStreamReader가 Reader를 구현하여 System.in으로 얻은 바이트를 문자로 변환해 BufferedReader와의 중간 역할을 한다.

(자세히 설명하자면 이것만으로도 글을 하나 작성할 수 있으니 짧게 설명하겠다, System.in이 반환하는 InputStream은 byte단위를 반환하고 InputStreamReader는 문자(유니코드) 단위를 반환하며 BufferedReader는 이것을 인자로 문자열을 반환한다.)

 

 

 

System의 in 메서드
InputStreamReader의 생성자.
BufferedReader의 생성자. 별도 사이즈 설정이 없으면 기본 값인 8192까지 저장한다.

 

 

 

 

 

 

 

스프링을 배운 사람이면 모두 한 번쯤 봤을만한 이 그림..

여기 나오는 핸들러 어댑터는 이름부터 어댑터라고 명시해놨다.

열심히 공부한 사람이라면 저게 정확하게 어떻게 굴러가는지는 몰라도 대략적으로 어떻게 작동하는지는 알 것이다.

 

 

 

 

LastModified는 Deprecated되었기 때문에 버리고 나머지만 살펴보자.

 

핸들러 어댑터는 코어 MVC 워크플로우의 prameterization을 위해 사용되는 MVC framework SPI라고 한다.

무슨 말인지 나도 모른다. 우리가 궁금한 것은 어댑터 패턴이니 아는 것만 읽자.

참고로 SPI는 그냥 "님들 쓰라고 만든 거 아니고 설계상 내부에서 사용되는 API같은 거예요"라고 알아들으면 된다.

 

어쩌고 저쩌고 길게 적혀져있는데 HandlerAdapter위 설명의 핵심은 "이게 DispatcherServlet의 확장성을 무제한으로 보장해주는 아주 중요한 친구입니다."라는 한 줄로 해결된다.

 

supports 메서드를 보면 핸들러 인스턴스(핸들링할 객체)를 받아서 핸들러아답터가 지원할 수 있는지 확인해준다고 한다.

한낱 메서드 주제에 그런 복잡한 일을 혼자서 다 한단 말이야?

믿음이 안 가니까 직접 확인해보자.

 

 

 

우선 HandlerAdapter의 supports를 사용하는 DispatcherServlet의 설명이다.

기본적으로 BeanNameUrlHandlerMapping과 RequestMappingHandlerMapping을 가지고 있으며 이러한 HandlerMapping을 통해 라우팅 요청을 컨트롤한다고 한다.

그 아래가 중요한데, DispatcherServlet은 모든 종류의 HandlerAdapter를 사용할 수 있으며, 기본적으로 HttpRequestHandlerAdapter와 SimpleControllerHandlerAdapter를 가지고 있다고 한다.  ( 각각 스프링의 HttpRequestHandler 및 Controller와 대응하는)

 

 

localhost8080으로 접속하자 DispatcherServlet의 getHandlerAdapter메서드에서 어댑터들을 반복문으로 돌리며 알맞는 핸들러를 찾고 있다.

 

 

 

 

단순히 String을 반환하는 정적 페이지를 요청했더니 HttpRequestHandlerAdapter를 배정해줬다.

 

 

 

의심이 많은 사람들을 위해 RestAPI 요청을 날렸더니 @RequestMapping 설정 때문에 RequestMappingHandlerAdapter가 불러와졌다.

SimpleControllerHandlerAdapter같은 경우는 어노테이션을 사용하지 않고 직접 Controller를 구현할 때나 사용되는 어댑터라서 거의 사용할 일은 없다.

 

 

 

어댑터가 정해지면 내부에서 나머지 설정을 마치고 필터 체인을 거쳐 요청이 해당 컨트롤러에 도착한다.

 

 

 

 

너무 길어서 이 부분은 캡쳐해오지 않았으나, 우리가 제일 많이 사용하고 있는 RequestMappingHandler 내부를 보면 정말 다양한 상황에 맞춰서 스프링 MVC에게 우리의 핸들러 코드를 실행할 수 있는 형태로 변환해주고 있는 것을 확인할 수 있다.

(어느 부분에서 캡처해야할 지 읽다가 포기했다.)

 

이런 어댑터 패턴의 장점으로는 기존 코드를 변경하지 않고 원하는 인터페이스 구현체를 만들어 재사용할 수 있으며, 기존 코드가 하던 일과 특정 인터페이스 구현체로 변환하는 작업을 각자 다른 클래스로 분리하여 관리할 수 있다는 점이다.

HandlerAdapter 덕분에 OCP(Open Closed Principal)가 잘 지켜지고 있는 것을 확인할 수 있다.

 

그러나 단점으로는 어댑터용으로 사용할 전용 인터페이스 혹은 클래스가 필요하기 때문에 클래스 구성이 복잡해질 수 있다.

내 개인적 의견으로는 당장은 클래스가 늘어나는 게 복잡도가 늘어나는 것 같아도, 객체지향 원칙을 잘 지키고 적절한 네이밍 센스를 발휘할 수 있다면 하나의 클래스 안에 이런 저런 기능을 모두 밀어넣는 것보다는 어댑터 패턴이 훨씬 좋지 않을까?라는 생각이 들었다.

 

물론 난 그냥 말하는 감자니까 내 의견은 크게 신경쓰지 않아도 된다.

끝.