[Spring] Spring과 SpringBoot
1. Framework란?
소프트웨어 개발에 있어서 하나의 뼈대 역할을 하는 것으로서, 자주 쓰일 만한 기능들을 모아 놓은 클래스와 라이브러리들의 집합이다.
2. Spring Framework
스프링은 Java 기반의 엔터프라이즈급 개발을 편리하게 만들어주는 오픈소스 경량급 애플리케이션 프레임워크
다음은 스프링 프레임워크의 특성들이다.
2. 1. 제어의 역전 (IoC; Inversion of Control)
객체를 사용할 때, 기존의 자바 개발의 경우 개발자가 직접 사용하려는 객체를 선언하여 해당 객체의 의존성을 생성한 후 객체를 사용하였다. 하지만 IoC를 특징으로 하는 스프링에서는 사용할 객체를 직접 생성하지 않고 객체의 생명주기 관리를 외부(Spring Container 혹은 IoC Container)에 위임한다. 객체의 관리를 컨테이너에 맡겨 제어권이 넘어간 것을 제어 역전이라고 부르며, 이를 통해 의존성 주입(DI), 관점 지향 프로그래밍(AOP) 등이 가능해진다.
2. 2. 의존성 주입 (DI; Dependency Injection)
먼저 의존성이란 무엇일까?
'A가 B에 의존한다'는 것은 의존대상 B가 변하면, 그것이 A에 영향을 미침을 의미한다. 즉, 의존대상이 변화하였을 때 A 또한 이에 맞게 수정해야 한다. 의존대상이 하나라면 모르겠지만 만약 수십, 수백개라면? 의존대상에 변동이 생길 때마다 소위 수많은 삽질성 노동이 필요할 것이다. 이는 객체지향프로그래밍의 SOLID 원칙 중 단일 책임 원칙*이 손상되는 상황이다.
* 단일 책임 원칙(Single Responsibility Principle) : 모든 클래스는 하나의 책임만 가지며, 클래스는 그 책임을 완전히 캡슐화해야 한다.
이를 해결하기 위해 우리는 의존성 주입이라는 방식을 사용할 수 있다 . 의존성 주입은 제어 역전의 방법 중 하나로, 사용할 객체를 직접 생성하지 않고 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식을 의미한다. A에서 B의 객체를 사용하는 경우, A 내부에서 B의 속성을 설정하는 것이 아니라 B 자체적으로 설정하고 A로 주입시키는 것이다.
의존성 주입의 구현 방법은 곧 하나의 클래스에서 외부 클래스 변수를 결정하는 방법이라고 볼 수 있는데, 크게 세 가지가 있다.
- 생성자를 통한 방법
@RestController
public class MyController {
MyService myService;
@Autowired
public MyController(MyService myService) {
this.myService = myService;
}
...
}
- 필드 객체 선언을 통한 방법
@RestController
public class MyController {
@Autowired
private MyService myService;
...
}
- Setter 메서드를 사용한 방법
@RestController
public class MyController {
private MyService myService;
@Autowired
public void setMyService(MyService myService) {
this.myService = myService;
}
...
}
2. 3. 관점 지향 프로그래밍 (AOP; Aspect-Oriented Programming)
AOP는 OOP(객체 지향 프로그래밍)를 더욱 효율적으로 사용하도록 돕는 개념으로서, 관점을 기준으로 묶어 개발하는 방식을 의미한다. 여기서 관점(aspect)이란, 서비스를 구성하고 있는 수많은 로직을 핵심 기능과 부가 기능으로 나누어 각각을 하나의 관점으로 보는 것을 의미한다. 위 그림에서 Transaction, Logging, Security을 부가 기능이라고 볼 수 있는데 이는 각기 다른 핵심 기능 안에 공통적으로 포함되어 중복을 유발한다. 이처럼 중복되는 부가 기능을 모듈화하여 삽입하는 방식을 AOP라고 한다.
2. 4. 스프링 프레임워크의 구조: 다양한 모듈
프로그램의 기능을 독립적인 부품으로 분리한 것을 모듈이라고 한다. 스프링 프레임워크는 약 20여 개의 모듈로 구성되어 있는데 이를 모두 사용해야하는 것이 아니라 필요한 것만 선택적으로 사용할 수 있다. 모듈로서 정의되어 있는 설정들 덕에 이전에 비해 개발자가 직접 작성해야 했던 부분들이 줄어들어, 이를 경량 컨테이너 설계라고 부른다.
3. Spring Boot
스프링 프레임워크는 위에서 '경량급'이라고 표현했듯 기존의 기술보다 복잡성을 크게 줄였지만 여전히 개발자가 직접 설정해주어야 하는 부분이 많았다. 이를 해결하기 위해 등장한 것이 스프링 부트이다. 스프링 부트는 스프링을 더 쉽게 사용할 수 있게 도와주는 별도의 프레임 워크로서, 개발자가 기존에 인프라 설정에 쓰던 소요를 줄여줌으로써 비즈니스 로직 개발에 더 집중할 수 있도록 도와준다.
다음은 스프링 부트의 특징들에 대해 정리해보았다.
3. 1. 1.의존성 관리
스프링 프레임워크에서는 개발에 필요한 각 모듈의 의존성을 직접 설정해야 했다. 또 호환되는 버전을 명시해야 정상 동작한다. 하지만 스프링 부트에서는 이 같은 불편함을 해소하기 위해 'spring-boot-starter'라는 의존성을 제공한다. 이는 각 라이브러리의 기능과 관련해서 자주 사용되고 서로 호환되는 버전의 모듈 조합을 제공한다. 이를 통해 개발자는 라이브러리 호환 문제를 해결할 수 있다.
3. 1. 2. 자동 설정
스프링 부트는 자동 설정(Auto Configuration) 기능을 통해 애플리케이션에 추가된 라이브러리를 실행하는 데 필요한 환경 설정을 알아서 관리해준다.
3. 1. 3. 내장 WAS
스프링 부트의 각 웹 애플리케이션에는 내장 WAS(Web Application Server)가 존재한다. 스프링 부트로 생성한 웹 애플리케이션 프로젝트에서 의존성을 확인해보면 위 사진과 같이 tomcat이 내장되어 있는 것을 확인할 수 있다. 따라서 특별한 설정 없이도 톰캣을 실행할 수 있다.
3. 1. 4. 모니터링
개발이 끝나고 서비스를 운영하는 시기에는 해당 시스템이 사용하는 스레드, 메모리, 세션 등의 주요 요소들을 모니터링해야 한다. 스프링 부트에는 Spring Boot Actuator라는 자체 모니터링 도구가 있다.
3. 2. 스프링 부트의 동작 방식
위 그림은 클라이언트로부터 웹 요청이 들어오고 내부 처리를 거쳐 다시 결과를 응답해주기까지의 동작 구조이다. 순서대로 알아보겠다.
- DispatcherServlet으로 요청(HttpServletRequest)이 들어오면 DispatcherServlet은 Handler Mapping을 통해 요청 URI에 매핑된 핸들러(Controller)를 탐색한다.
- HandlerAdapter로 핸들러(Controller)를 호출한다.
- HandlerAdapter에 컨트롤러로부터의 응답이 돌아오면 ModelAndView로 응답을 가공해 반환한다. View 형식으로 리턴하는 컨트롤러를 사용할 때는 View Resolver를 통해 View를 받아 리턴한다.
[참고 자료] 『스프링 부트 핵심 가이드』 장정우 지음