Spring의 탄생과 제어의 역전 (Framework vs Library)

nbh·2025년 10월 26일

"왜 Spring을 사용해야 할까?"

Java로 웹 애플리케이션을 개발할 때, Spring Framework는 거의 표준처럼 사용된다. 하지만 이 강력한 도구가 처음부터 당연하게 존재했던 것은 아니다. Spring이 등장하기 이전의 엔터프라이즈 개발 환경은 지금과 매우 달랐으며, 심각한 문제들을 안고 있었다.

Spring의 탄생 배경과 이로 인해 정립된 '프레임워크'와 '라이브러리'의 근본적인 차이점을 이해하는 것은 Java 개발자에게 필수적인 기초 역량이다.


1. Spring Framework는 왜 탄생했는가?

Spring의 등장은 EJB(Enterprise JavaBeans)라는 기술이 주도하던 2000년대 초반의 Java 엔터프라이즈 환경에 대한 반작용에서 시작되었다. 당시 EJB는 트랜잭션, 보안, 분산 처리 등 기업용 애플리케이션에 필요한 복잡한 기능들을 제공했지만, 개발자들에게 감당하기 힘든 문제점들을 안겨주었다.

A. EJB 시대의 문제점

  1. 극심한 복잡성: EJB를 사용하기 위해서는 수많은 XML 설정 파일과 상속받아야 하는 인터페이스, 원격 호출을 위한 별도의 객체 등, 실제 비즈니스 로직과 관계없는 상용구(Boilerplate) 코드가 너무 많이 필요했다.
  2. 무거운 환경 (Heavyweight): EJB는 EJB 컨테이너를 포함하는 무거운 '애플리케이션 서버'(WebLogic, WebSphere 등)에서만 동작했다. 이는 애플리케이션을 한 번 실행하고 테스트하는 데 수 분이 걸릴 정도로 개발 속도를 저하시켰다.
  3. 강한 결합과 침투성 (Intrusive): 비즈니스 로직을 담고 있는 순수한 Java 객체가 EJB 관련 API에 직접 의존해야 했다. 이로 인해 코드는 특정 기술(EJB)에 강하게 종속되었고, 다른 환경에서 재사용하거나 테스트하기가 불가능에 가까웠다.
  4. 테스트의 어려움: EJB 컨테이너 없이는 코드가 동작하지 않았기 때문에, 간단한 비즈니스 로직을 테스트하는 것조차 서버를 구동해야 하는 복잡한 '통합 테스트'가 되어버렸다.

B. Spring이 해결하고자 한 문제

2002년, 로드 존슨(Rod Johnson)은 이러한 EJB의 문제점들을 비판하며 더 나은 대안을 제시했다. 이것이 Spring Framework의 시작이었다.

Spring이 해결하고자 한 핵심 문제는 "개발자가 비즈니스 로직이라는 본질에만 집중할 수 있게 하자"는 것이었다.

  1. POJO (Plain Old Java Object) 프로그래밍: Spring은 EJB와 달리 특정 기술에 종속되지 않는 '평범한 Java 객체'(POJO)를 사용하여 비즈니스 로직을 구현하도록 했다. 이는 코드가 특정 환경이나 기술로부터 자유로워짐을 의미했다.
  2. 의존성 주입 (DI)과 제어의 역전 (IoC): 객체의 생성과 생명 주기 관리를 개발자가 직접 하는 것이 아니라, Spring 컨테이너가 대신 처리하도록 했다. (IoC) 이를 통해 객체 간의 의존성을 외부에서 주입(DI)받게 되면서 결합도가 극도로 낮아졌다.
  3. AOP (관점 지향 프로그래밍): 트랜잭션, 로깅, 보안처럼 여러 비즈니스 로직에서 공통으로 필요한 부가 기능(공통 관심사)들을 실제 비즈니스 코드에서 분리해냈다. 이로써 비즈니스 로드는 순수하게 자신의 논리에만 집중할 수 있게 되었다.
  4. 경량 컨테이너: 무거운 애플리케이션 서버가 아닌, Tomcat 같은 가벼운 '서블릿 컨테이너'에서도 애플리케이션이 충분히 동작할 수 있게 만들었다.

결국 Spring은 EJB의 복잡성을 걷어내고, 낮은 결합도(Decoupling)높은 테스트 용이성(Testability)을 가진 유연한 애플리케이션을 만들 수 있는 환경을 제공했다.


2. Framework vs Library: 제어 흐름의 차이

Spring을 '프레임워크'라고 부르는 이유는 '라이브러리'와 근본적인 차이점이 있기 때문이다. 이 차이를 구분하는 핵심 기준은 "제어 흐름의 주체가 누구인가?"이다.

A. Library (라이브러리)

라이브러리는 개발자가 제어 흐름의 주체가 된다.
마치 '도구 상자'와 같다. 개발자는 필요할 때마다 도구(라이브러리)를 가져와서 사용하고, 언제 사용할지, 어떻게 사용할지를 직접 결정한다.

  • 사용 방식: 내 코드(애플리케이션)가 라이브러리의 코드를 호출(Call)한다.
  • 예시 (Java의 ArrayList):
// 개발자가 직접 'ArrayList' 라이브러리를 생성하고 호출한다.
// 제어의 흐름은 개발자의 코드에 있다.
List<String> myList = new ArrayList<>();

myList.add("Data1"); // 필요할 때 호출
myList.add("Data2"); // 필요할 때 호출

// 라이브러리는 호출되었을 때만 동작한다.
System.out.println(myList.get(0));

B. Framework (프레임워크)

프레임워크는 프레임워크가 제어 흐름의 주체가 된다. '잘 지어진 뼈대'나 '설계도'와 같다. 프레임워크는 전체적인 구조와 동작 흐름을 이미 가지고 있으며, 개발자는 그 뼈대 속의 비어 있는 공간에 자신의 코드를 작성해 끼워 넣는다.

사용 방식: 프레임워크의 코드가 내 코드(개발자가 작성한 코드)를 호출(Call)한다.

이를 제어의 역전 (IoC, Inversion of Control)이라고 부른다. "Don't call us, we'll call you." (우리를 부르지 마세요, 우리가 당신을 부를 겁니다.)라는 할리우드 원칙으로도 유명하다.

예시 (Spring Framework의 @RestController):


// 개발자는 'MyController' 클래스와 'hello()' 메서드를 정의할 뿐,
// 이 코드를 언제, 어떻게 실행할지 결정하지 않는다.
@RestController
public class MyController {

    @GetMapping("/hello")
    public String hello() {
        // 이 메서드는 개발자가 직접 호출하지 않는다.
        return "Hello, Spring!";
    }
}
// 웹 브라우저에서 "/hello" 요청이 들어오면,
// Spring Framework(의 DispatcherServlet)가 이 'hello()' 메서드를
// 대신 찾아서 실행(호출)하고 응답을 처리한다.

결론

Spring Framework는 EJB의 복잡성을 해결하기 위해 '제어의 역전(IoC)'이라는 개념을 도입하여 개발자가 비즈니스 로직에만 집중할 수 있도록 만들었다. 라이브러리가 개발자의 코드에 의해 호출되는 수동적인 '도구'라면, 프레임워크는 개발자의 코드를 호출하는 능동적인 '뼈대'다.

이러한 도구들의 철학적 차이를 이해하는 것은, 우리가 특정 기술을 '왜' 그리고 '어떻게' 사용해야 하는지에 대한 명확한 기준을 제시해 준다.

0개의 댓글