스프링 부트 3의 상위 프레임워크인 스프링을 비교하며 스프링 부트 3에 대해 알아보고, 스프링의 콘셉트인 IoC(제어의 역전), DI(의존성 주입), AOP(관점 지향 프로그래밍), PSA(이식 가능한 서비스 추상화)를 알아본 다음 스프링 부트 3 프로젝트를 만들며 스프링 부트 3를 시작해보겠습니다.
총 2편입니다. 1편에서는 스프링의 원리를 알아보고, 2편에서는 간단한 예제로 스프링 부트를 이해해봅시다.
[Spring] 스프링 부트 3 시작하기❶
1. 그림으로 이해하는 프로젝트
다음은 이번에 진행할 프로젝트와 실습 구성입니다. 처음으로 포스트맨으로 GET 요청을 전송하는 단계이므로 그 구성을 그림으로 표현하였습니다.
그림을 보면 TestController 클래스가 웹 브라우저의 요청을 받아 test( ) 메서드를 실행하여 문자열을 반환하고 있습니다. 웹 브라우저의 요청을 특정 클래스의 특정 메서드가 어떻게 처리하는지 나타낸 것입니다.
2. 스프링과 스프링 부트
스프링 프레임워크를 알아보고 나서 스프링 부트를 알아봅니다. 그 뒤에는 스프링 프레임워크와 스프링 부트가 어떻게 다른지 알아보겠습니다.
2.1 스프링의 등장
엔터프라이즈 애플리케이션이라는 용어가 있습니다. 웹 개발이 처음인 여러분에게는 매우 생소한 용어일 텐데요. 엔터프라이즈 애플리케이션은 대규모의 복잡한 데이터를 관리하는 애플리케이션을 말합니다. 소프트웨어 분야가 발전하며 엔터프라이즈 애플리케이션은 점점 복잡해졌습니다. 예를 들어 은행 시스템을 생각해보면 몇 백만, 아니 몇 천만의 사람이 한꺼번에 잔고 조회를 하고, 입금이나 출금 요청을 하거나 새로운 통장을 개설하기도 합니다. 이렇듯 엔터프라이즈 애플리케이션은 많은 사용자의 요청을 동시에 처리해야 하므로 서버 성능과 안정성, 보안이 매우 중요합니다. 그런데 이런 것들을 신경쓰면서 사이트 기능, 즉, 비즈니스 로직까지 개발하기는 매우 어렵습니다. 누군가 엔터프라이즈 애플리케이션을 위한 개발 환경을 제공해서 기능 개발에만 집중할 수 있다면 얼마나 좋을까요?
이런 상황에서 2003년 6월에 스프링 프레임워크가 짠하고 등장했습니다. 스프링 프레임워크는 앞서 언급한 서버 성능, 안정성, 보안을 매우 높은 수준으로 제공하는 도구였죠. 덕분에 개발자들은 기능 개발에 집중할 수 있게 되었습니다.
2.2 스프링을 더 쉽게 만들어주는 스프링 부트
스프링은 장점이 많은 개발 도구이지만 설정이 매우 복잡하다는 단점이 있습니다. 개발팀도 스프링의 이런 단점을 인식하고 보완하고자 스프링 부트를 출시했습니다(2013년 4월 0.5.0.M6 버전 첫공개). 스프링 부트는 스프링 프레임워크를 더 쉽고 빠르게 이용할 수 있도록 만들어주는 도구입니다. 빠르게 스프링 프로젝트를 설정할 수 있고 의존성 세트라고 불리는 스타터를 사용해 간편하게 의존성을 사용하거나 관리할 수 있습니다. 스프링 부트는 개발자가 조금 더 비즈니스 로직 개발에만 집중할 수 있도록 만들어주는 도구인 것이죠. 스프링과 비교했을 때 스프링 부트의 주요 특징을 다음과 같이 정리할 수 있습니다.
💡 스프링 부트의 주요 특징
- 톰캣, 제티, 언더토우 같은 웹 애플리케이션 서버(web application server, WAS)가 내장되어 있어서 따로 설치를 하지 않아도 독립적으로 실행할 수 있습니다.
- 빌드 구성을 단순화하는 스프링 부트 스타터를 제공합니다.
- XML 설정을 하지 않고 자바 코드로 모두 작성할 수 있습니다.
- JAR를 이용해서 자바 옵션만으로도 배포가 가능합니다.
- 애플리케이션의 모니터링 및 관리 도구인 스프링 액츄에이터(spring actuator)를 제공합니다.
참고로 스프링 부트와 스프링이 다른 도구라고 생각하는 사람들이 있는데요. 스프링 부트는 스프링에 속한 도구입니다. 단, 스프링과 스프링 부트는 개발할 때의 몇 가지 차이점이 있죠. 그 차이점도 조금 짚어보겠습니다.
차이점 1. 구성의 차이
가장 먼저 구성의 차이점이 있습니다. 스프링은 애플리케이션 개발에 필요한 환경을 수동으로 구성하고 정의해야 합니다. 하지만 스프링 부트는 스프링 코어와 스프링 MVC의 모든 기능을 자동으로 로드하므로 수동으로 개발 환경을 구성할 필요가 없습니다.
차이점 2. 내장 WAS의 유무
스프링 애플리케이션은 일반적으로 톰캣과 같은 WAS에서 배포됩니다. WAS란 웹 애플리케이션 서버(Web Application Server)의 약자입니다. 하지만 스프링 부트는 WAS를 자체적으로 가지고 있습니다. 그래서 jar 파일만 만들면 별도로 WAS를 설정하지 않아도 애플리케이션을 실행할 수 있습니다. 참고로 스프링 부트의 내장 WAS에는 톰캣, 제티, 언더토우가 있어서 상황에 필요한 WAS를 선택할 수도 있습니다. 그 외의 차이점을 표로 정리하겠습니다. 공부를 시작하기 전에 간단히 읽어보고 넘어가기 바랍니다.
▼ 스프링과 스프링 부트 특징 비교
3. 스프링 콘셉트 공부하기
본격적인 스프링 부트 공부를 하기 전에 스프링이라는 프레임워크가 돌아가는 원리를 이해하기 위해서 스프링 콘셉트를 우선 공부하고 넘어가겠습니다. 실습 전에 공부할 내용이 너무 많은 것 같아서 머리가 아플 수도 있겠지만 한 번은 그냥 읽어보고 넘어가기를 권합니다. 여기서는 스프링의 중요한 콘셉트라 할 수 있는 제어의 역전과 의존성 주입을 먼저 알아보고 스프링 컨테이너와빈에 대한 개념을 알아보겠습니다.
3.1 제어의 역전과 의존성 주입
스프링은 모든 기능의 기반을 제어의 역전(IoC)과 의존성 주입(DI)에 두고 있습니다. 이후 제어의 역전은 IoC로, 의존성 주입은 DI라고 줄여 부르겠습니다.
IoC란?
IoC는 Inversion of Control을 줄인 표현입니다. 직역하면 제어의 역전이죠. 조금 어렵게 들리겠지만 자바를 공부한 여러분이라면 충분히 이해할 수 있는 말입니다. 여러분이 지금까지 자바 코드를 작성해 객체를 생성할 때는 객체가 필요한 곳에서 직접 생성했을 겁니다. 다음을 보면 클래스 B 객체를 사용하기 위해 클래스 A에서 객체를 직접 생성합니다.
▼ 클래스 A에서 클래스 B 객체 생성 예
제어의 역전은 다른 객체를 직접 생성하거나 제어하는 것이 아니라 외부에서 관리하는 객체를 가져와 사용하는 것을 말합니다. 위 예제에 제어의 역전을 적용하면 다음과 같이 코드의 형태로 바뀝니다. 이전과는 다르게 클래스 B 객체를 직접 생성하는 것이 아니므로, 어딘가에서 받아와 사용하고 있다고 추측해볼 수 있죠. 실제로 스프링은 스프링 컨테이너가 객체를 관리, 제공하는 역할을 합니다.
▼ 스프링 컨테이너가 객체를 관리하는 방식 예
DI란?
앞에서 설명한 것처럼 스프링에서는 객체들을 관리하기 위해 제어의 역전을 사용합니다. 그리고 제어의 역전을 구현하기 위해 사용하는 방법이 DI입니다. 여기서 DI라는 개념이 등장합니다. DI는 Dependency Injection을 줄인 표현이고, 직역하면 의존성 주입입니다.
DI는 어떤 클래스가 다른 클래스에 의존한다는 뜻입니다. 조금 어려운 표현이라고 생각하겠지만 이것도 코드를 통해 보면 매우 쉽습니다. 다음은 IoC/DI를 기초로 하는 스프링 코드입니다. 여기에서 사용하는 @Autowired라는 애너테이션은 스프링 컨테이너에 있는 빈이라는 것을 주입하는 역할을 하는데요. 빈은 쉽게 말해 스프링 컨테이너에서 관리하는 객체를 말합니다. 빈은 바로 다음에 설명할 개념이므로 우선은 이 정도만 이해하고 넘어가도 됩니다. 이전 코드에서는 개발자가 직접 B 객체를 생성했지만 다음 코드는 어딘가에서 B b;라고 선언했을 뿐 직접 객체를 생성하지는 않고 있습니다. 다시 말해 객체를 주입받고 있습니다.
▼ 객체를 주입받는 모습 예
이렇게 코드를 작성해도 프로그램은 잘 동작합니다. 그 이유는 스프링 컨테이너라는 곳에서 객체를 주입했기 때문입니다. 쉽게 말해 스프링 컨테이너가 B 객체를 만들어서 클래스 A에 준 겁니다.
그림처럼 기존의 자바 코드는 클래스 A에서 B 객체를 쓰고 싶은 경우 직접 생성했지만, 스프링의 경우 클래스 A에서 B 객체를 쓰고 싶은 경우 객체를 직접 생성하는 것이 아니라 스프링 컨테이너에서 객체를 주입받아 사용합니다. 이 IoC/DI 개념은 스프링의 핵심 개념이라고 할 수 있을 만큼 중요하기 때문에 반드시 이해하고 넘어가기 바랍니다.
3.2빈과 스프링 컨테이너
스프링 컨테이너란?
앞서 언급했던 것처럼 스프링은 스프링 컨테이너를 제공합니다. 스프링 컨테이너는 빈을 생성하고 관리합니다. 즉, 빈이 생성되고 소멸되기까지의 생명주기를 이 스프링 컨테이너가 관리하는 것이죠. 또한 개발자가 @Autowired 같은 애너테이션을 사용해 빈을 주입받을 수 있게 DI를 지원하기도 합니다. 그럼 빈은 도대체 무엇일까요?
빈이란?
앞에서도 설명했지만 빈은 스프링 컨테이너가 생성하고 관리하는 객체입니다. 앞에서 본 코드에서 B가 바로 빈인데요, 스프링은 빈을 스프링 컨테이너에 등록하기 위해 XML 파일 설정, 애너테이션 추가 등의 방법을 제공합니다. 다시 말해 빈을 등록하는 방법은 여러 가지가 있다는 뜻이죠.
예를 들어 MyBean이라는 클래스에 @Component 애너테이션을 붙이면 MyBean 클래스가 빈으로 등록됩니다. 이후 스프링 컨테이너에서 이 클래스를 관리하죠. 이때 빈의 이름은 클래스 이름의 첫 글자를 소문자로 바꿔 관리합니다. 따라서 MyBean 클래스의 빈 이름은 myBean이겠네요.
▼ 클래스를 빈으로 등록하는 방법 예
어렵게 생각할 필요 없이 스프링에서 제공해주는 객체라고 생각하면 됩니다.
3.3 관점 지향 프로그래밍
스프링에서 또 하나 중요한 개념으로 AOP가 있습니다. AOP는 Aspect Oriented Programming을 줄인 표현입니다. 직역하면 관점 지향 프로그래밍이죠. 조금 의미를 풀어 설명하자면 프로그래밍에 대한 관심을 핵심 관점, 부가 관점으로 나누어서 관심 기준으로 모듈화하는 것을 의미합니다. 이것도 이해가 조금 어려울 테니 좀 더 쉬운 예를 통해 설명해보겠습니다.
예를 들어 계좌 이체, 고객 관리하는 프로그램이 있을 때 각 프로그램에는 로깅 로직, 즉, 지금까지 벌어진 일을 기록하기 위한 로직과 여러 데이터를 관리하기 위한 데이터베이스 연결 로직이 포함됩니다. 이때 핵심 관점은 계좌 이체, 고객 관리 로직이고, 부가 관점은 로깅, 데이터베이스 연결 로직입니다. 실제 프로그램의 기능으로 로직을 정리하면 다음 그림과 같겠네요.
그림을 보면 로깅, 데이터베이스 연결은 모두 계좌 이체와 고객 관리에 필요합니다. 여기에 AOP 관점을 적용하면 부가 관점에 해당하는 로직을 모듈화해 앞에서 본 그림처럼 개발할 수 있게 해줍니다. 다시 말해 부가 관점 코드를 핵심 관점 코드에서 분리할 수 있게 해주죠. 그 결과 프로그래머는 핵심 관점 코드에만 집중할 수 있게 될 뿐만 아니라 프로그램의 변경과 확장에도 유연하게 대응할 수 있어 좋습니다.
3.4 이식 가능한 서비스 추상화
마지막으로 알아볼 스프링 콘셉트는 이식 가능한 서비스 추상화입니다. 이후 이식 가능한 서비스 추상화를 PSA라고 부르겠습니다. PSA는 Portable Service Abstraction을 줄인 표현인데요, 풀어서 설명하자면 스프링에서 제공하는 다양한 기술들을 추상화해 개발자가 쉽게 사용하는 인터페이스를 말합니다.
웹 개발이 처음이면 이 설명도 어렵게 들릴 수 있습니다. 예를 들어 설명해보겠습니다. 대표적인 PSA의 예로는 클라이언트의 매핑과 클래스, 메서드의 매핑을 위한 애너테이션이 있습니다. 예를들어 스프링에서 데이터베이스에 접근하기 위한 기술로는 JPA, MyBatis, JDBC 같은 것들이 있는데요, 여기에서 어떤 기술을 사용하든 일관된 방식으로 데이터베이스에 접근하도록 인터페이스를 지원합니다. 또 다른 예시로는 WAS도 PSA의 예시 중 하나라고 볼 수 있는데요. 코드는 그대로 두고 WAS를 톰캣이 아닌 언더토우, 네티와 같은 다른 곳에서 실행해도 기존 코드를 그대로 사용할 수 있으니까요.
지금까지 스프링의 콘셉트인 IoC, DI, AOP, PSA에 알아봤습니다. 이 기술들을 기반으로 스프링이 만들어졌으므로 이 개념은 반드시 알고 넘어가는 게 좋습니다. 스프링 프레임워크는 IoC/DI를 통해 객체 간의 의존 관계를 설정하고, AOP를 통해 핵심 관점과 부가 로직을 분리해 개발하며, PSA를통해 추상화된 다양한 서비스들을 일관된 방식으로 사용하도록 합니다.
지금까지 내용을 한 줄로 정리하면 이렇게 정리할 수 있습니다.
💡한 줄로 정리하는 스프링 핵심 4가지
- IoC : 객체의 생성과 관리를 개발자가 하는 것이 아니라 프레임워크가 대신하는 것
- DI : 외부에서 객체를 주입받아 사용하는 것
- AOP : 프로그래밍을 할 때 핵심 관점과 부가 관점을 나누어서 개발하는 것
- PSA : 어느 기술을 사용하던 일관된 방식으로 처리하도록 하는 것
다음 편에서는 본격적으로 스프링 부트에 대해 알아봅시다!
신선영
리멤버 백엔드 개발자. 하드 스킬과 소프트 스킬 역량을 강화하고자 부단히 공부하고 글로 남기는 백엔드 개발자입니다. 평일 기준 하루 평균 600뷰의 기술 블로그를 운영하고, 모교 학생을 대상으로 정기 세미나와 멘토링을 진행합니다. 구독자가 1,000명 정도 되는 사이드 프로젝트를 기획하고 개발하고 운영한 경험이 있습니다.
저자 블로그 shinsunyoung.tistory.com
저자 깃허브 github.com/shinsunyoung