가장 많이 쓰이는 서버 프레임워크 중 하나인 Spring 프레임워크에 대해 알아보았다. 본 글은 완벽하게 Spring 프레임워크의 구조를 분석하기 보다는 다른 프레임워크와의 차이점, 특징등을 파악하기 위해 작성되었다.
Spring 프레임워크
JAVA 기반의 오픈 소스 어플리케이션 프레임워크이며 주로 동적 웹 프로그래밍에 많이 쓰인다. 사용작 많은 오픈소스이기 때문에 규모가 매우 크고 대부분의 기능들이 개발되어 있다는 장점이 있다. 그 외에 특징은
특징
- 객체를 Bean이라는 인터페이스로 직접 관리한다.
- 여기서 우리가 흔히 아는 Ioc(Inversion of control), DI(Dependancy Injection)이라는 개념이 사용된다. - 기본적으로 Multi Thread 방식을 사용한다.
- 사실 제일 궁금했던 부분이다. 다중 접속 처리를 위해 Thread Pool에 Thread를 만들어 두고 Client 요청 하나에 Thread를 하나 할당하는 방식을 사용한다.(톰캣 기반 Spring 기준) - 기본적으로 싱글톤 패턴을 이용해 Bean에 접근한다.정확히는 싱글톤 패턴 자체를 이용한다기 보다는, 싱글톤 컨테이너를 이용해서 내부적으로 객체 인스턴스를 1개의 인스턴스로 조절하는 것이다.
- 멀티스레드에서 싱글톤 패턴을 사용한다니... 라고 걱정할수도 있지만, 당연히 개발자는 Bean 인스턴스의 내부 필드에는 동기화 문제를 생각하면서 설계해야 한다. - AOP(Aspect Oriented Programming) - 관점 지향 프로그래밍을 사용한다. AOP란 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 해당 관점들을 각각 모듈화하여 프로그래밍 하는 것이다.
- 모듈화하면 공통적인 기능들을 모듈로 대체하면 되므로 중복 코드가 발생할 소지가 매우 적어진다. - MVC(Model - View - Controller) 패턴을 이용한다.
아마 프레임워크에서 객체의 소멸, 생성을 관리하기 위해 내부적으로 각 객체에 대한 리플렉션을 통해 구현되는 것으로 예상된다.. 언리얼 엔진에서 사용하는 방법들과도 매우 비슷한거 같다..
MVC 패턴
스프링 프레임워크의 기본 구조인 MVC 패턴에 대해 알아보자. 사실 웹 서버를 해봤으면 디자인 패턴 중 하나인 MVC 패턴은 매우 친숙한데, 그림과 같이 Model, View, Controller로 나누어서 3가지 구성 요소로 개발을 진행하는 방식이다.
Model - 정보 및 데이터를 담당하는 부분으로, 주로 Controller에게 받은 데이터를 가공하여 View에게 전달해준다. 실제 물리적인 Model이 존재하기 보다는, View와 Controller 사이의 데이터를 Model이라고 생각하자.
View - 사용자에게 보여지는 화면으로, 모델로 부터 받은 데이터를 통해 화면을 구성한다.
Controller - Model과 View 사이에서 비즈니스 로직을 실행한다. 로직을 수행한 후 뷰에 전달할 데이터를 모델에 담아 보내준다.
이처럼 MVC 패턴은 로직을 구분하고 독립적으로 처리하여 유지보수가 간편하다는 장점이 있다.
스프링 내부 MVC 패턴
스프링 프레임워크에서는 MVC 패턴을 응용하여 개선된 MVC 패턴을 사용한다. 많은 코드들의 중복을 제거하고 Controller와 Service를 분리하여 Controller는 서비스 앞단에서 파라미터를 검증하고, 서비스에서 비즈니스 로직을 수행한다. 둘의 분리를 통해 공통적인 Service를 범용적으로 사용할 수 있다는 장점이 있다.
- Request에 대한 요청을 처리 할 수 있는 Handler(Controller)를 검색
- 각 Handler에 대한 Adapter를 찾는다.
- 찾은 Adapter를 통해 Controller에 요청을 보내준다.
- Adapter에서 Controller에 필요한 입력을 넘겨준다.
- Controller에서 비즈니스 로직을 수행한다.
- Controller를 통해 얻은 결과를 통해 Adapter에서 View에 대한 정보를 넘겨준다.
- View에 대한 정보(ModelAndView)를 View Resolver에게 넘겨주고
- View Resolver로 부터 받은 View를 응답으로 넘겨준다.
이제 중요한 구조를 개별적으로 살펴보면
Dispatcher Servlet
Dispatcher Servlet의 역할은 그림에서 같이 유저의 요청(url)에 따라 알맞은 Controller를 찾아주고, 입력을 넘겨준다는 데에 있다. Dispatcher Servlet은 결국, Front Controller로 가장 먼저 앞에서 요청과 응답을 처리해준다는 특징이 있다.
그렇다면 Dispatcher Servlet은 왜 사용하는 것일까? 만약 Dispatcher Servlet이 없다면 어떤 일이 일어나게 될까?
좌측의 일반적인 경우에, 각 Controller에 요청을 전달해주게 되면 Controller 내부에 공통적인 처리 부분을 중복 코드로 작성하여야 한다. 예를들어, 유효하지 않은 요청에 대한 처리라던가, 파라미터를 검증하는 부분들이 있을 것이다.
우측처럼 중간에 Front Controller를 두어 처리를 해준다면, 공통적인 부분들을 Front Controller에서 처리해주므로 중복 코드 작성을 줄일 수 있고, 공통 처리 부분을 수정할 때도 Front Controller만 수정해주면 되므로, 유지보수적 관점에서도 좋다는 장점이 있다!
Handler Adapter
Adapter 패턴은 주로, 입력이나 출력이 서로 다른 인터페이스들을 마치 하나의 공통적인 인터페이스처럼 사용할 수 있도록 해주는 것이다. 우리가 생각하는 케이블 어댑터를 떠올리면 될 것이다.. 예를 들면,
class Runner
{
void Run(int num);
}
class Walker
{
void Walk(int num, int hour);
}
class WalkerToRunnerAdapter : public Runner
{
void Run(int num)
{
Walk(num, 1);
}
}
Walker, Runner는 다른 인터페이스이지만 WalkerToRunnerAdapter를 통해 Walker를 Runner처럼 Run()이라는 함수를 사용할 수 있게 된다.
스프링 내부에서도 사용자가 직접, 다양한 입력이나 출력들을 사용하는 Controller를 구현할 수 있도록 Dispatcher Servlet에서 직접 Controller에 접근하는 것이 아닌, 중간에 Adapter를 두어 다양한 Controller를 지원하도록 한 것이다.
또 이렇게 되면 Controller에서 특정 모듈에 대한 의존성도 제거할 수 있다는 장점이 있다. 만약 모든 Controller가 특정 모듈에서 사용하는 클래스를 입력으로 받는다면, 해당 모듈에 의존성을 가진 Controller가 되지만, 중간에 Adapter를 두어 해당 모듈을 각 Controller에 맞는 입력으로 변환해준 후 넘겨준다면, Controller에서는 해당 모듈에 대한 의존성이 사라진다!
결론
이전에 스프링을 사용했을때 멀티스레드에 대한 동기화 문제를 생각하지 않고 프로그래밍했을때 문제가 발생하지 않았던 것 같은데, 아마도 웹 서버의 특징때문에 그런 것 같다. HTTP/HTTPS 통신 자체가 Stateless이기 때문에 공통 유저들에 대한 정보에 접근하는 부분보다는 각 유저들의 요청에 대해 특정 서비스 로직에 접근하여 해당 서비스에서 처리만 해주는 부분이 많기 때문이라고 생각한다. 또 만약 데이터에 접근할 때에도 DB 자체 트랜젝션에 대한 Lock을 관리하기 때문에 만약 데이터에 접근하더라도 DB 단에서 이를 해결해주었기 때문이라고 생각한다...
상세한 스프링에 대한 설명보다는 전체적인 특징과 서버 프레임워크(특히 웹서버)에 대해 궁금했던 점들을 위주로 정리해보았다. 근데 역시, 내부 구조는 언리얼 엔진이랑 비슷한 것을 보면, 결국 플랫폼만 다를 뿐 개발자들의 고민이나 문제 - 해결방법들은 비슷한 양상을 보여주는 것 같다.
'서버' 카테고리의 다른 글
[C++] 메모리 풀(Memory Pool) 구현 (1) | 2024.09.24 |
---|---|
[서버구조분석] NodeJS 프레임워크 기본구조 분석( 부제 : 멀티스레드 vs 싱글스레드 ) (0) | 2024.04.11 |
락 프리(Lock-Free) 알고리즘 (4) | 2024.03.13 |
소켓 통신 프로그래밍(2) (1) | 2024.03.06 |
소켓 통신 프로그래밍 정리(1) (1) | 2024.03.05 |