# 8장 스프링이란 무엇인가?

스프링은 단순히 `IOC/DI`를 편하게 적용하도록 돕는 단계를 넘어서 엔터프라이즈 애플리케이션 개발의 전 영역에 걸쳐 다양한 종류의 기술에 관여한다.

* 그렇다면 과연 `스프링`이란 무엇이고 어떻게 설명할 수 있을까?
* `스프링 프레임워크`가 만들어진 `이유`와 존재 `목적`, 추구하는 `가치`는 무엇 일까?

## 스프링의 정의

스프링을 그때그때 필요한 `API` 사용 방법 위주로만 공부하면 스프링을 오해하거나 그 가치를 충분히 누리지 못할 수 있다. 그래서 한 번쯤은 스프링의 정의를 통해 스프링이 어떤 것인지 큰 그림으로 이해해보려고 노력할 필요가 있다. 스프링에 대해 가장 잘 알려진 정의는 이렇다.

> 자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크

### 애플리케이션 프레임워크

프레임워크는 애플리케이션의 특정 계층에서 주로 동작하는 한 가지 기술 분야에 집중된다. 하지만 스프링은 이와 다르게 '`애플리케이션 프레임워크`'라는 특징을 갖고 있다.

> 애플리케이션 프레임워크란?

애플리케이션 프레임워크는 `특정 계층`이나, `기술`, `업무 분야`에 국한되지 않고 애플리케이션의 전 영역을 포괄하는 범용 적인 프레임워크를 뜻한다. 애플리케이션 프레임워크는 애플리케이션 개발의 전 과정을 빠르고 편리하며 진행하는데 일차적인 목표를 두는 프레임워크다.

재미있게도 스프링의 기원은 `J2EE` 기술 서적에 딸린 예제 코드다. 스프링을 처음 만든 사람은 로드 존슨이라는 유명한 자바 개발자다. `로드 존슨`은 2003년에 '`Expert One-on-One j2EE Design and Development`'라는 책을 출간했다. 당연히 책의 예제 애플리케이션도 프레임워크를 먼저 만들고 나서, 프레임워크를 이용하는 코드를 만드는 방식으로 작성됐다. 바로 이 예제에 포함된 프레임워크가 스프링 프레임워크의 기원이다.

#### 스프링의 오해

스프링을 `Ioc/DI` 프레임워크나 `AOP` 툴이라고 보는 이유는 스프링이 제공하는 핵심 기술에만 주목했기 때문이다. 스프링의 일차적인 존재 목적은 핵심 기술에 담긴 프로그래밍 모델을 일관되게 적용해서 엔터프라이즈 애플리케이션 전 계층과 전 영역에 전략과 기능을 제공해줌으로써 애플리케이션을 편리하게 개발하게 해주는 애플리케이션 프레임워크로 사용되는것임을 기억해두자

### 경량급

스프링이 `경량급`이라는 건 스프링 자체가 아주 가볍다거나 작은 규모의 코드로 이뤄졌다는 뜻은 아니다. 오히려 스프링은 수십만 라인에 달하는 코드를 가진 매우 복잡하고 방대한 규모의 프레임워크다.

#### 그렇다면 스프링이 가볍다고 하는 이유는 무엇일까?

당시 `EJB`는 기술에 대한 과도한 욕심으로 인해 `개발환경`과 `운용 서버`, `개발`과 `빌드`, `테스트 과정`, 작성된 코드 모두를 매우 무겁고 복잡하게 만들었다. `EJB`가 동작하려면 고가의 느리고 무거운 자바 서버(`WAS`)가 필요했다. 그로 인해 고가의 제품으로 구성된 제대로 된 개발 환경을 갖추지 않고는 개발하기가 힘들었다.

그에 반해 스프링은 가장 단순한 서버 환경인 `톰캣`이나 `제티`에서도 완벽하게 동작한다. 서블릿 컨테이너만으로 충분하니 `EJB` 컨테이너를 비롯해 복잡한 기능이 잔뜩 포함된 `고급 WAS`를 굳이 사용하지 않아도 된다. 코드는 더 단순하고 개발 과정은 편리하면서도 `EJB`에서조차 불편했던 고급 기능을 세련된 방식으로 적용할 수 있다.

만들어진 코드가 지원하는 기술 수준은 비슷하더라도 그것을 훨씬 빠르고 간편하게 작성하게 해줌으로써 `생산성`과 `품질` 면에서 유리하다는 것이 바로 `경량급`이라는 말로 표현되는 스프링의 특징이다.

### 자바 엔터프라이즈 개발을 편하게

애플리케이션 개발이란 개발자가 복잡하고 실수하기 쉬운 `로우 레벨 기술`에 많은 신경을 쓰지 않으면서도 애플리케이션의 핵심인 사용자의 요구사항, 즉 비즈니스 로직을 빠르고 효과적으로 구현하는 것을 말한다. 엔터프라이즈 개발에서 필연적으로 요구되는 기술적인 요구를 충족 하면서도 개발을 복잡하게 만들지 않는다는 점이 스프링의 뛰어난 면이다.

### 오픈소스

스프링은 `오픈소스` 프로젝트 방식으로 개발돼왔다. 오픈소스란 말 그대로 소스가 모두에게 공개되고, 특별한 라이선스를 취득할 필요없이 얼마든지 가져다 자유롭게 이용해도 된다는 뜻이다. 다만 스프링을 사용한다는 점과 원 저작자를 밝히고 제품을 패키징할 때 `라이선스 정보`를 포함시키는 등의 기본적인 의무 사항을 따르면 된다. 또, 필요하다면 스프링 소스코드를 가져와 수정해서 사용할 수도 있다. 수정을 했더라도 수정한 소스를 공개해야 하는 의무는 없다.

`오픈소스의 장점`은 공개된 커뮤니티의 공간 안에서 투명한 방식으로 `다양한 참여`를 통해 개발되기 때문에 매우 빠르고 `유연한 개발`이 가능하다는 것이다. 그러다 보니 다양한 환경에서 개발하는 개발자가 자신이 경험한 문제점이나 발견한 버그 등을 그때마다 `커뮤니티`를 통해 개발팀에게 전달하기 때문에 잠재적인 `버그`와 `문제점`이 빠르게 발견되고 해결될 수 있다.

#### 오픈소스 개발 모델에는 단점도 있다.

`지속적`이고 `안정적`인 개발이 계속 될지가 `불확실`하다는 것이다. 스프링 같은 프레임워크는 기업의 가장 중요한 핵심 업무를 관장하는 엔터프라이즈 시스템의 개발에 사용된다. 그래서 오픈 소스 개발이라는 방법을 선택하기는 했지만 프레임워크 사용자에게 지속적인 신뢰를 줄 수 있도록 개발을 책임지고 진행할 수 있는 전문 기업을 만들었다. 덕분에 안정적이고 `전문화된 개발`과 `품질 관리`가 가능해졌다.

## 스프링의 목적

#### 스프링의 개발 철학과 궁극적인 목표가 무엇인지를 생각해보자.

스프링을 제대로 사용하는 건 생각보다 쉽지 않다. `레퍼런스 매뉴얼`을 착실히 읽고 관련 서적을 여러 권 공부한다고 해도 스프링을 사용해 어떻게 개발해야 할지 막막할 수도 있다.

결국 `스프링의 목적`을 바로 이해하고, 그 목적을 이루는 도구로 스프링을 잘 활용 해야만 스프링으로부터 제대로 된 가치를 얻을 수 있다.

### 엔터프라이즈 개발의 복잡함

엔터프라이즈 시스템 개발은 왜 복잡할까? 크게 `두 가지 원인`을 생각해볼 수 있다.

#### 기술적인 제약조건과 요구사항이 늘어난다.

엔터프라이즈 시스템은 많은 `사용자의 요청`을 동시에 처리해야 하기 때문에 `서버의 자원`을 효율적으로 `공유`하고 `분배`해서 사용할 수 있어야 한다. 따라서 `뛰어난 성능`과 `서비스의 안전성`이 요구되고 그런 점을 고려한 개발 기술이 필요하다. 문제는 이러한 엔터프라이즈 시스템의 기술적인 요구사항은 단순히 `고가의 애플리케이션 서버`나 `툴`을 사용한다고 충족될 수 있는게 아니라는 점이다. 따라서 이런 종류의 기술적인 문제를 고려하면서 애플리케이션을 개발해야 하는 부담을 안게 된다.

#### 비즈니스 로직의 복잡함이 증가한다.

2000년 전후로 전 세계에 불어 닥친 경제위기가 기업의 체질을 크게 바꾸는 계기가 되었다. `수시로` 업무 프로세스를 `변경`하고 조종하는 것을 상시화할 만큼 `변화의 속도가 빨라졌다`. 결국 이런 `업무 구조`와 `프로세스`의 변화는 이를 뒷받침해줘야 하는 엔터프라이즈 시스템의 변경을 요구할 수밖에 없었다. `버그`나 `오류`가 있어서가 아니라, 기능 요구 사항과 업무 정책 등이 바뀌기 때문에 애플리케이션을 자주 `수정` 해줘야 하는 시대가 된 것이다. 그만큼 이전과 다르게 `시스템 개발`과 `유지보수`등의 작업에 대한 `부담`은 커지고 그에 따른 개발의 난이도는 더욱 증가한 것이다.

자바 엔터프라이즈 시스템 개발이 어려운 가장 큰 이유는 `근본적인 비즈니스 로직`과 `엔터프라이즈 기술`이라는 두 가지 복잡함이 한데 얽혀 있기 때문이다.

#### 실패한 해결책: EJB

`EJB`의 기본 전략도 이 두가지 종류의 복잡함을 분리하는 것이었다. 개발자가 `로우레벨`의 기술적인 복잡함에 신경 쓰지 않고 `비즈니스 로직`을 효과적으로 개발하는 데 더 집중할 수 있게 하자는 목표가 있었다. EJB는 기술적인 복잡함을 애플리케이션의 핵심 로직에서 일부분 `분리`하는 데 성공하긴 했다. `선언적 트랜잭션`이나 `선언적 보안`, `컨테이너를 통한 리모팅 기술의 적용`, `컴포넌트 단위의 배치`, `JNDI`를 통한 서비스 검색 지원, `서비스 오브젝트의 풀링`, `컴포넌트 생명주기` 관리 등은 EJB의 목표를 어느 정도 충족 시켰다. 그러나 EJB라는 환경과 `스펙에 종속되는 코드`로 만들어져야 하는 더 큰 `부담`을 안게 되었다. `EJB`라는 틀 안에서 자바 코드를 만들게 강제함으로써 자바 언어가 원래 갖고 있던 장점마저 잃어버였다는 사실이다. 게다가 `EJB`의 `발전주기`는 너무 느려서 엔터프라이즈 개발 기술의 발전을 따라잡지 못하는것도 문제점이다.

### 복잡함을 상대하는 스프링의 전략

#### 기술에 대한 접근 방식이 일관성이 없고, 특정 환경에 종속적이다

`일관성 없는 기술`과 `서버환경의 변화`에 대한 스프링의 공략 방법은 바로 `서비스 추상화`다. 기술적인 복잡함은 일단 추상화를 통해 `로우 레벨의 기술 구현 부분`과 `기술을 사용하는 인터페이스를 분리`하고, `환경`과 세부기술에 독립적인 접근 인터페이스를 제공하는 것이 가장 좋은 해결책이다. 스프링이 제공하는 `템플릿/콜백 패턴`은 판에 박힌 반복적인 작업 흐름과 API 사용 코드를 제거해준다.

#### 기술적인 처리를 담당하는 코드가 성격이 다른 코드에 섞여서 등장한다

`AOP`는 최후까지 애플리케이션 로직을 담당하는 코드에 남아 있는 기술 관련 코드를 깔끔하게 분리해서 별도의 모듈로 관리하게 해주는 강력한 기술이다. `AOP`는 기술을 다루는 코드로 복잡함이 기술 그 자체 이상으로 불필요하게 증대되지 않도록 도와주는 가장 강력한 수단이다.

### 비즈니스와 애플리케이션 로직의 복잡함을 상대하는 전략

`비침투적인 기술`인 스프링은 핵심 로직을 다루는 코드에는 스프링의 흔적조차 찾을 수 없을 만큼 자신을 드러내지 않는다. **다만 뒤에서 비즈니스 로직을 담당하는 오브젝트들에게 적절한 엔터프라이즈 기술 서비스가 제공되도록 은밀히 도와줄 뿐이다.**

#### 핵심 도구: 객체지향과 DI

스프링의 모토는 결국 "`기본으로 돌아가자`"이다. 자바의 기본인 객체 지향에 충실한 설계가 가능하도록 단순한 오브젝트로 개발할 수 있고, `객체 지향의 설계 기법`을 잘 적용할 수 있는 구조를 만들기 위해 `DI` 같은 유용한 기술을 편하게 적용하도록 도와주는 것이 `스프링의 기본 전략`이다.

`서비스 추상화`, `템플릿/콜백`, `AOP`와 같은 스프링의 기술은 DI 없이는 존재할 수 없는 것들이다.

스프링을 사용하면 순수한 비즈니스 로직만을 담고 있는 코드에는 객체지향 분석과 설계에서 나온 도메인 모델을 쉽게 적용할 수 있기 때문이다. 객체지향적인 특정을 잘 살린 설계는 `상속`과 `다형성`, `위임`을 포함해서 많은 `객체지향 디자인 패턴`과 `설계 기법`이 잘 녹아들어 갈 수 있었다.

## POJO 프로그래밍

`분리됐지만 반드시 필요한 엔터프라이즈 서비스 기술을 POJO 방식으로 개발된 애플리케이션 핵심 로직을 담은 코드에 제공한다`'는 것이 스프링의 가장 강력한 특징과 목표다.

![](https://2649832514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M5HOStxvx-Jr0fqZhyW%2F-MFLifs6fw1XEBPtJXbk%2F-MFLir2kBmzgPMgqT0J5%2F8-1.png?alt=media\&token=313706f8-9189-4fe1-adfa-86b96cd2263e)

DI의 기본 아이디어는 유연하게 확장 가능한 오브젝트를 만들어두고 그 관계는 외부에서 다이내믹하게 설정해준다는 것이다.

### POJO란 무엇인가?

`POJO`는 `Plain Old Java Object`의 첫 글자를 따서 만든 약자다. 단순하게 보자면 그냥 평범한 자바 오브젝트라고 할 수 있지만 좀 더 명확하게 하자면 적어도 다음의 `세 가지 조건`을 충족해야 `POJO`라고 불릴 수 있다.

#### 특정 규약에 종속되지 않는다

`POJO`는 `자바 언어`와 꼭 필요한 `API` 외에는 종속되지 않아야 한다.\*\* 별다른 큰 가치를 주지도 못하는 규약 따위에 종속되지 않아야 하고, 객체지향 설계의 `자유로운 적용`이 가능한 오브젝트여야만 `POJO`라고 불릴 수 있다.

#### 특정 환경에 종속되지 않는다

`특정 환경`에 종속적이어야만 동작하는 오브젝트도 `POJO`라고 할 수 없다.\*\* 특히 비즈니스 로직을 담고 있는 클래스나 인터페이스를 사용해서는 안 된다. `진정한 POJO`란 객체지향적인 원리에 충실하면서, 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트를 말한다.

### POJO의 장점

`특정한 기술`과 `환경`에 종속되지 않는 오브젝트는 그만큼 깔끔한 코드가 될 수 있다. 또 `POJO`로 개발된 코드는 자동화된 테스트에 매우 유리하다. 환경의 제약은 코드의 자동화된 테스트를 어렵게 한다.

## 스프링의 기술

스프링에는 `POJO` 프로그래밍을 손쉽게 할 수 있도록 지원하는 세 가지 가능 기술을 제공한다. 그 세 가지 기술은 바로 `IoC/DI`, `AOP`, `PSA`다.

스프링의 기술들은 스프링 프레임워크가 만들어진 진정한 목표인 POJO 기반의 엔터프라이즈 개발을 편리하게 해주는 도구일 뿐이다.

### 제어의 역전(IoC) / 의존관계 주입(DI)

**왜 두 개의 오브젝트를 분리해서 만들고, 인터페이스를 두고 느슨하게 연결한 뒤, 실제 사용할 대상은 DI를 통해 외부에서 지정하는 것일까?**

가장 간단한 답변은 '`유연한 확장이 가능하게 하기 위해서`'라고 할 수 있다. DI는 `OCP`라는 객체지향 설계 원칙으로 잘 설명될 수 있다.

#### DI의 활용 방법

* 핵심기능의 변경
* 핵심기능의 동적인 변경
* 부가기능의 추가
* 인터페이스의 변경
* 프록시
* 템플릿과 콜백
* 싱글톤과 오브젝트 스코프
* 테스트

### 관점 지향 프로그래밍(AOP)

#### AOP의 적용 기법

* `다이내믹 프록시`를 사용한다
* 자바 언어의 `한계`를 넘어서는 `언어의 확장`을 이용한다.

### 포터블 서비스 추상화(PSA)

`환경`과 `세부 기술`의 변화에 관계없이 일관된 방식으로 기술에 접근할 수 있게 해주는 `PSA`다. `**POJO`로 개발된 코드는 특정 환경이나 구현 방식에 종속적이지 않아야 한다.\*\*

스프링의 `서비스 추상화`의 `개념`과 `장점`을 잘 이해한다면 때에 따라 직접 서비스 추상화 기법을 적용할 필요도 있다. 서비스 추상화를 위해 필요한 기술은 `DI`뿐이다. 결국 `DI` 응용 방법의 한 가지이므로 DI를 적극 활용해서 개발한다면 서비스 추상화는 자연스럽게 만들어 쓸 수 있다.
