스프링 부트 웹 어플리케이션 개발에 앞서 알고 있어야 할 기초 지식에 대해 다루어보자.
마이크로서비스 아키텍처
어떤 포털 사이트에서 블로그, 카페, 메일 등 지원하는 서비스들을 하나의 어플리케이션에 통합해 개발한다고 가정하자. 만약 이렇게 구성한다면, 서버를 업데이트 하거나 어플리케이션 유지보수를 할 때마다 모든 서비스를 중단하고 작업을 진행할 수 밖에 없게 되며, 서비스 자체의 규모도 커져 구동하는 데 걸리는 시간도 길어지게 된다. 이런 문제를 해결하기 위해 나온 것이 마이크로서비스 아키텍처(Microservice Architecture)이다.
모놀리식 서비스 아키텍처와 마이크로서비스 아키텍처 비교1
마이크로서비스 아키텍처는 어플리케이션을 핵심 기능별로 세분화해 구성한다. 앞의 포털 사이트를 블로그 프로젝트, 카페 프로젝트, 메일 프로젝트로 나누어 개발하는 것이다. 각 서비스는 독립적인 프로젝트이기 때문에, 어떠한 언어든지 요구사항에 맞게 개발할 수 있고, 개발자는 오직 특정 서비스만 집중하기 때문에 코드에 대해서 상세히 파악할 수 있어 구현단계에서 효율을 높일 수 있다는 장점이 있다.
서비스를 기능별로 구분해서 독립적인 어플리케이션을 개발하게 되면 각 서비스 간에 통신해야 하는 경우가 발생하는데, 이를 서버 간 통신이라고 한다. 이 때 통신은 아래와 같은 프로토콜(=규칙)에 의해 다양한 방식을 적용할 수 있다.
HTTP
HTTP는 Hyper Text Transfer Protocol의 약자로, 하이퍼텍스트 문서(HTML)를 교환하기 위해서 만들어진 프로토콜이다. HTTP는 비연결성 프로토콜이기 때문에 요청/응답(클라이언트-서버)방식으로 동작한다. HTTP는 웹에서만 사용하는 프로토콜로서 TCP/IP를 기반으로 동작한다.
- 문제점 2
- HTTP는 텍스트 통신이라고 할수 있는데 누군가 중간에서 가로챈다면 내용이 노출되어 보안상의 문제가 있다.
- 통신 상대를 확인하지 않기 때문에 변조가 가능하다.
이런 보안상의 문제를 해결하기 위해 HTTPS가 나타났다.
HTTPS
HTTP와 HTTPS 비교2
HTTPS는 기존의 HTTP 레이어 밑에 SSL 이나 TLS 같은 보안 레이어가 추가된 프로토콜이다. 송신 측은 요청과 응답 데이터를 네트워크로 보내기 전에 보안 레이어에서 암호화 하고, 수신 측은 이 레이어에서 복호화 해 HTTP 레이어로 보낸다.
보안 레이어는 보안 인증서 방식를 통해 데이터를 암호화 하고 안정성을 검증받는다. 인증서란 클라이언트와 서버간의 통신을 제 3자가 보증을 해주는 문서이다. 송신 측은 데이터를 보내기 전, 이 보증 기관으로부터 인증서를 받아 암호화 한 데이터와 함께 수신 측에 보낸다. 수신 측은 받은 인증서를 보증 기관에 확인해 이 데이터가 안전한 데이터인지 확인하고 동시에 복호화에 필요한 키를 받아 데이터를 복호화 한다.
보안 레이어에서 사용하는 프로토콜은 SSL 과 TSL이 있다. SSL은 90년대 중반 넷스케이프에 의해서 생성되었지만, 현재는 폐기된 프로토콜이다. TLS는 IETF에서 유지 및 관리하는 웹의 보안 암호화를 위한 새로운 프로토콜이다.3
SSH
Secure Shell Protocol의 약자로, 안전하지 않은 네트워크 환경에서 원격지 host에 안전하게 접속하기 위해 사용되는 프로토콜이다. 즉, URL과는 관련이 없고, 원격으로 서버를 제어하거나 서버에 데이터를 보낼 때 사용하는 프로토콜이다. HTTPS와 마찬가지로 데이터를 대칭키 및 공개키 방식으로 암호화 해 유출의 위험을 줄인다. 또 서버 제어권을 획득하기 위해 비밀번호를 사용하면 비밀번호가 네트워크를 통해 교환되기 때문에 위험성이 존재하는데, SSH는 공개키 인증 방식을 사용하므로 보안상 더욱 안전하다.4
SOAP
Simple Object Access Protocol(단순 객체 접근 프로토콜)의 약자로, HTTP, HTTPS 등을 통해 XML 기반의 메시지를 컴퓨터 네트워크 상에서 교환하는 프로토콜이다. 웹서비스(Open API)를 제공할 때 사용되는 프로토콜이자 해당 프로토콜 기반으로 만들어진 아키텍처이다. 같은 기능을 하는 REST 방식에 비해 구조가 복잡하고, 속도가 느리기 때문에 현재는 잘 사용하지 않는다고 한다.
스프링 부트의 MVC 모델
스프링 부트에서 spring-boot-starter-web
모듈을 사용하면 톰캣을 사용하는 스프링 MVC 구조를 기반으로 동작한다. MVC란, Model, View, Controller 의 합성어로, 소프트웨어 공학에서 사용되는 소프트웨어 디자인 패턴이다. Model은 백그라운드에서 동작하는 로직을 처리하고, View는 사용자가 보게 될 결과 화면을 출력, Controller는 이 두 레이어 사이에서의 흐름을 제어한다. 톰캣은 WAS(Web Application Server)를 제공하는 대표적인 서비스 중 하나로, 서블릿을 통해 요청에 맞는 컨트롤러를 호출해 처리한 결과로 동적 컨텐츠를 반환, 스프링 컨테이너와 함께 MVC 구조에서 V와 C를 담당해 자동으로 처리한다.
서블릿은 서블릿 컨테이너에서 관리하는데, 서블릿 컨테이너는 다음과 같은 특징을 가지고 있다:
- 각 요청마다 스레드를 생성하여 처리하는 멀티 스레딩을 지원한다.
- 서블릿 컨테이너는 서블릿 객체의 생명주기를 관리한다.
- 같은 요청이 올 때마다 새로운 객체를 만드는 것은 비효율적이므로, 객체를 싱글톤으로 관리해 같은 요청은 같은 인스턴스를 사용하도록 함.
스프링 MVC 구조5
스프링에서는 톰캣의 디스패처 서블릿(Dispatcher Servlet)이 서블릿 역할을 한다.
클라이언트로부터 요청이 들어오면 서버는 다음과 같은 순서로 요청을 처리한다: 5
- 핸들러 조회: 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.
- 핸들러 어댑터 조회: 핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다.
- 핸들러 어댑터 실행: 핸들러 어댑터를 실행한다.
- 핸들러 실행: 핸들러 어댑터가 실제 핸들러를 실행한다.
- ModelAndView 반환: 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환한다.
- viewResolver 호출: 뷰 리졸버를 찾고 실행한다. JSP의 경우 InternalResourceViewResolver가 자동 등록되고, 사용된다.
- View 반환:뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환한다. JSP의 경우 InternalResourceView(JstlView)를 반환한다. 내부에 forward() 로직이 있다.
- 뷰 렌더링: 뷰를 통해서 뷰를 렌더링한다.
핸들러 매핑은 요청 정보를 기준으로 어떤 컨트롤러를 사용할지 선정하는 인터페이스이다. 스프링은 기본적으로 5개의 다른 전략을 기용하는 구현체를 제공한다.[^]
BeanNameUrlHandlerMapping
빈의 이름에 들어 있는 URL을 HTTP 요청의 URL 과 비교해서 일치하는 빈을 찾아 준다. 빈을 정의할 때 슬래시(‘/’)가 들어가면 매핑 대상이 되고, ‘*’, ‘**’, ‘?’와 같은 와일드 카드를 사용하는 패턴을 넣을 수도 있다.
ControllerBeanNameHandlerMapping
빈의 아이디나 빈 이름을 이용해 매핑해주는 전략이다. 빈의 아이디가 hello 로 선언되었다면, /hello URL에 매핑해주는 것이다.
ControllerClassNameHandlerMapping
클래스의 이름과 같은 URL에 매핑해주는 전략이다. 클래스의 이름이 Controller로 끝나는 경우, Controller를 제외한 나머지 부분을 추가적으로 매핑 대상으로 삼는다.
SimpleUrlHandlerMapping
URL 패턴에 매핑된 컨트롤러를 사용하는 전략이다. 매핑할 컨트롤러 빈의 이름을 직접 넣어줘야 하기 때문에 오타 등의 오류가 발생할 가능성이 있다.
DefaultAnnotationHandlerMapping
@RequestMapping
이라는 애노테이션을 컨트롤러 클래스나 메소드에 직접 부여하고 이를 이용해 매핑하는 전략이다.
레이어드 아키텍처
레이어드 아키텍처(Layered Architecture)란 애플리케이션의 기능들을 유사 관심사를 기준으로 레이어로 묶어 수평적으로 구성한 구조이다. 각 레이어는 자신의 고유 역할을 수행하고, 인접한 다른 레이어에 무언가를 요청하거나 응답한다. 그 밖의 다른 레이어는 신경 쓸 필요가 없기 때문에, 각 레이어는 자신의 역할에 충실할 수 있다. 또, 기능별로 레이어를 나눴기 때문에, 시스템 전체를 수정하지 않고 특정한 레이어의 기능이나 성능을 개선하는 것이 가능해진다.
스프링 레이어드 아키텍처6
레이어드 아키텍처는 일반적으로 3계층 또는 4계층으로 나뉘는데, 3계층으로 이뤄진 레이어드 아키텍처는 다음과 같은 형태를 가진다.
프레젠테이션 계층 클라이언트의 요청을 해석하고 응답을 보내는 계층이며, 스프링의 Dispatcher Servlet이 담당하는 부분으로 MVC중 V와 C가 모두 여기에 속한다.
비즈니스 계층 서비스 계층이라고도 하며, 핵심 비즈니스 로직을 구현하는 계층이다. 즉, 여기서부터 개발자가 구현해야하는 부분이다. 트랜잭션 처리나 유효성 검사 등의 작업도 수행한다.
데이터 접근 계층 프로그램이 종료되어도 데이터가 사라지지 않도록 저장하는 곳이므로, 영속(Persistence) 계층이라고도 한다. CRUD 연산을 하거나 비즈니스 로직에서 필요한 데이터를 DTO에 담아 다시 비즈니스 계층으로 보내는 역할이다.
디자인 패턴
디자인 패턴(Design Pattern)은 소프트 웨어를 설계할 때 자주 발생하는 문제들을 해결하기 위해 고민된 해결책들을 말한다. 디자인 패턴을 구체화해서 정리한 대표적인 분류방식으로 ‘GoF 디자인 패턴’이라는 것이 있다.
생성(Creational) 패턴 | 구조(Structural) 패턴 | 행위(Behavioral) 패턴 |
---|---|---|
추상 팩토리(Abstract Factory) | 어댑터(Adapter) | 책임 연쇄(Chain of Responsibility) |
빌더(Builder) | 브리지(Bridge) | 커맨드(Command) |
팩토리 메서드(Factory Method) | 컴포지트(Composite) | 인터프리터(Interpreter) |
프로토타입(Prototype) | 데코레이터(Decorator) | 이터레이터(Iterator) |
싱글톤(Singleton) | 파사드(Facade) | 미디에이터(Mediator) |
플라이웨이트(Flyweight) | 메멘토(Memento) | |
프락시(Proxy) | 옵저버(Observer) | |
스테이트(State) | ||
스트레티지(Strategy) | ||
템플릿 메서드(Template Method) | ||
비지터(Visitor) |
GoF 디자인 패턴은 생성 패턴, 구조 패턴, 행위 패턴 총 세 가지로 구분된다.
생성 패턴
객체 생성에 사용되는 패턴으로, 객체를 수정해도 호출부가 영향을 받지 않게 하는 디자인 패턴이다.
- 추상 팩토리: 구체적인 클래스를 지정하지 않고 상황에 맞는 객체를 생성하기 위한 인터페이스를 제공하는 패턴이다.
- 빌더: 객체의 생성과 표현을 분리해 객체를 생성하는 패턴이다.
- 팩토리 메서드: 객체 생성을 서브클래스로 분리해서 위임하는 패턴이다.
- 프로토타입: 원본 객체를 복사해 객체를 생성하는 패턴이다.
- 싱글톤: 한 클래스마다 인스턴스를 하나만 생성해서 인스턴스가 하나임을 보장하고 어느 곳에서도 접근할 수 있게 제공하는 패턴이다.
구조 패턴
객체를 조합해서 더 큰 구조를 만드는 패턴이다.
- 어댑터: 클래스의 인터페이스를 의도하는 인터페이스로 변환하는 패턴이다.
- 브리지: 추상화와 구현을 분리해서 각각 독립적으로 변형케 하는 패턴이다.
- 컴포지트: 여러 객체로 구성된 복합 객체와 단일 객체를 클라이언트에서 구별 없이 다루는 패턴이다.
- 데코레이터: 객체의 결합을 통해 기능을 동적으로 유연하게 확장할 수 있게 하는 패턴이다.
- 파사드: 서브시스템의 인터페이스 집합들에 하나의 통합된 인터페이스를 제공하는 패턴이다.
- 플라이웨이트: 특정 클래스의 인스턴스 한 개를 가지고 여러 개의 ‘가상 인스턴스’를 제공할 때 사용하는 패턴이다.
- 프락시: 특정 객체를 직접 참조하지 않고 해당 객체를 대행하는 객체를 통해 접근하는 패턴이다.
행위 패턴
객체 간의 알고리즘이나 책임 분배에 관한 패턴이다. 객체 하나로는 수행할 수 없는 작업을 여러 객체를 이용해 작업을 분배한다. 결합도 최소화를 고려할 필요가 있다.
- 책임 연쇄: 요청 처리 객체를 집합으로 만들어 결합을 느슨하게 만드는 패턴이다.
- 커맨드: 실행될 기능을 캡슐화해서 주어진 여러 기능을 실행하도록 클래스를 설계하는 패턴이다.
- 인터프리터: 주어진 언어의 문법을 위한 표현 수단을 정의하고 해당 언어로 구성된 문장을 해석하는 패턴이다.
- 이터레이터: 내부 구조를 노출하지 않으면서 해당 객체의 집합 원소에 순차적으로 접근하는 방법을 제공하는 패턴이다.
- 미디에이터: 한 집합에 속한 객체들의 상호작용을 캡슐화하는 객체를 정의한 패턴이다.
- 메멘토: 객체의 상태 정보를 저장하고 필요에 따라 상태를 복원하는 패턴이다.
- 옵저버: 객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버 목록을 객체에 등록해 상태가 변할 때마다 메서드 등을 통해 객체가 직접 옵저버에게 통지하게 하는 디자인 패턴이다.
- 스테이트: 상태에 따라 객체가 행동을 변경하게 하는 패턴이다.
- 스트래티지: 행동을 클래스로 캡슐화해서 동적으로 행동을 바꿀 수 있게 하는 패턴이다.
- 템플릿 메서드: 일정 작업을 처리하는 부분을 서브클래스로 캡슐화해서 전체 수행 구조는 바꾸지 않으면서 특정 단계만 변경해서 수행하는 패턴이다.
- 비지터: 실제 로직을 가지고 있는 객체(visitor)가 로직을 적용할 객체(element)를 방문하며 실행하는 패턴이다.
출처
https://velog.io/@ghkstmd00/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98 ↩
https://wonyong-jang.github.io/web/2020/03/25/Web-http-https.html ↩ ↩2
https://velog.io/@woply/spring-%EC%8A%A4%ED%94%84%EB%A7%81-MVC%EC%9D%98-%EC%A0%84%EC%B2%B4-%EA%B5%AC%EC%A1%B0-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0 ↩ ↩2