스프링 프레임워크란 무엇인가

스프링 프레임워크란

스프링 프레임워크는 자바 또는 코틀린 기반 엔터프라이즈 애플리케이션을 더 단순하고 유연하게 개발할 수 있도록 돕는 오픈소스 프레임워크입니다.

스프링은 개발자가 애플리케이션의 핵심 흐름과 비즈니스 로직에 더 집중할 수 있도록 하고, 그 밖의 공통적이고 반복적인 작업은 프레임워크 차원에서 일관되게 지원합니다.

스프링이 지향한 방향은 다음과 같습니다.

객체 간 결합도를 낮추는 구조

기존에는 필요한 객체를 애플리케이션 코드가 직접 생성하고 연결하는 경우가 많았기 때문에, 하나의 객체가 다른 객체의 구체적인 구현에 강하게 의존하기 쉬웠습니다. 이런 구조에서는 구현이 바뀌면 관련 코드도 함께 수정해야 했고, 변경의 영향 범위도 커졌습니다. 스프링은 객체의 생성과 관리를 컨테이너가 담당하도록 하여 객체 간 결합을 줄이고, 더 유연한 구조를 만들 수 있게 했습니다.

테스트하기 쉬운 코드

코드가 특정 컨테이너나 기술 구현체에 강하게 묶여 있으면 단위 테스트를 작성하기가 어렵고, 작은 기능 하나를 검증하는 데도 많은 환경 구성이 필요해집니다. 반면 스프링이 지향한 방식은 비즈니스 로직을 가능한 한 POJO 안에 두고, 필요한 의존관계는 외부에서 구성하는 방식입니다. 이런 구조는 테스트 대상만 분리해서 검증하기 쉬우며, 대체 구현이나 테스트용 객체를 적용하기도 수월합니다.

기술 구현체에 덜 종속적인 애플리케이션 설계

엔터프라이즈 애플리케이션은 데이터 접근, 트랜잭션 처리, 메시징 등 다양한 기반 기술을 사용합니다. 문제는 이런 기술이 바뀌거나 구현체가 달라질 때 애플리케이션 코드까지 변경해야 하는 경우가 많았다는 점입니다. 스프링은 여러 기술을 일관된 방식으로 다룰 수 있는 추상화 계층을 제공함으로써, 애플리케이션 코드가 특정 구현에 과도하게 묶이지 않도록 했습니다.

반복되는 설정 코드의 축소

과거에는 JDBC를 직접 사용할 때 연결 획득, 자원 반납, 예외 처리 같은 코드가 여러 곳에서 반복되기 쉬웠습니다. 트랜잭션 처리 역시 비즈니스 로직마다 비슷한 코드가 함께 작성되는 경우가 많았습니다. 스프링은 이러한 반복적인 작업을 프레임워크 차원에서 지원하여, 개발자가 같은 패턴의 코드를 계속 작성하지 않도록 했습니다. 그 결과 핵심 로직이 더 또렷하게 드러나고, 코드의 양도 줄일 수 있었습니다.

엔터프라이즈 개발에서 필요한 공통 기능의 표준화

로깅, 트랜잭션, 예외 처리, 데이터 접근 지원 같은 기능은 많은 애플리케이션에서 반복적으로 필요합니다. 스프링은 이러한 기능을 개별 프로젝트마다 제각각 구현하기보다, 공통된 방식으로 적용할 수 있는 기반을 제공했습니다. 이는 개발 생산성을 높이는 데 그치지 않고, 애플리케이션 전반의 구조와 동작 방식을 더 일관되게 유지하는 데에도 도움이 되었습니다.

오늘날에는 스프링 부트를 주로 사용하는 경우가 많지만, 그 기반은 스프링 프레임워크입니다.


등장 배경

스프링이 등장한 이유를 이해하려면, 먼저 스프링 이전의 자바 엔터프라이즈 개발이 어떤 문제를 가지고 있었는지 볼 필요가 있습니다. 당시 대규모 웹 애플리케이션과 업무 시스템은 주로 Java EE 진영의 기술을 중심으로 개발되었고, 그중 대표적인 기술이 EJB였습니다.

EJB는 엔터프라이즈 개발에 필요한 기능을 제공했지만, 사용 방식이 복잡했고 애플리케이션 코드가 특정 기술과 강하게 결합되는 문제가 있었습니다. 이러한 EJB의 복잡성을 줄이고, 더 가볍고 단순한 방식으로 엔터프라이즈 애플리케이션을 개발할 수 있게 하기 위해 스프링이 등장했습니다.

EJB의 복잡성

EJB는 트랜잭션, 보안, 분산 처리 같은 엔터프라이즈 기능을 제공했지만, 개발자가 이를 활용하는 과정은 단순하지 않았습니다. 오히려 비즈니스 로직을 작성하는 것보다 EJB 설정을 맞추는 데 더 많은 비용이 들기도 했습니다.

경량 컨테이너의 필요성

EJB 기반 개발의 부담이 커지면서, 더 가볍고 단순한 방식으로 객체를 관리할 수 있는 컨테이너가 필요해졌습니다. 여기서 말하는 컨테이너는 애플리케이션에서 사용하는 객체를 생성하고, 초기화하고, 필요할 때 연결해 주는 실행 환경을 뜻합니다.

스프링은 무거운 엔터프라이즈 서버에 강하게 의존하지 않으면서도, 애플리케이션에 필요한 객체 관리 기능을 제공하는 경량 컨테이너를 지향했습니다. 이로 인해 개발자는 객체를 직접 전부 조립하는 대신, 컨테이너가 애플리케이션 구성 요소를 관리하도록 맡길 수 있게 되었습니다.

POJO 기반 개발의 필요성

POJO는 Plain Old Java Object의 약자로, 특정 프레임워크나 컨테이너에 강하게 종속되지 않은 일반적인 자바 객체를 뜻합니다.

과거에는 비즈니스 로직을 작성할 때도 특정 기술의 상속 구조나 인터페이스를 따라야 하는 경우가 많았다. 이러한 방식은 코드가 기술 구현에 묶이게 만들고, 핵심 로직의 의미를 모호하게 만들었습니다.

스프링은 가능한 한 비즈니스 로직을 POJO 안에 두고, 프레임워크가 그 바깥에서 필요한 기능을 제공합니다. 핵심 로직과 설정 코드의 역할이 분리되기 때문에 코드의 유지보수성이 높아집니다.


핵심 특징

스프링 프레임워크는 애플리케이션 구조를 더 유연하게 만들기 위한 몇 가지 핵심 개념을 중심으로 동작하는데, 그중 대표적인 특징이 IoC 컨테이너, AOP 지원, 포터블 서비스 추상화입니다.

IoC 컨테이너

IoC 컨테이너

IoC는 Inversion of Control, 즉 제어의 역전입니다. 전통적인 방식에서는 애플리케이션 코드가 필요한 객체를 직접 생성하고, 필요한 시점에 직접 호출하는 경우가 많았습니다. 반면 스프링에서는 객체의 생성과 생명주기 관리 같은 책임을 프레임워크가 맡습니다.

이때 중요한 역할을 하는 개념이 IoC 컨테이너이다. IoC 컨테이너는 애플리케이션에서 사용하는 객체를 생성하고, 설정 정보를 바탕으로 관리하며, 필요한 객체를 서로 연결합니다. 스프링에서는 이렇게 컨테이너가 관리하는 객체를 보통 빈(Bean) 이라고 부릅니다.

IoC 컨테이너 구조의 장점은 다음과 같습니다.

AOP

AOP

애플리케이션에는 핵심 비즈니스 로직과 별개로 여러 곳에서 반복적으로 등장하는 공통 기능이 있습니다. 대표적으로 로깅, 트랜잭션 처리, 보안 검사, 성능 측정 같은 기능이 해당합니다.

이러한 기능을 모든 클래스와 메서드에 직접 작성하면 코드가 중복되고, 핵심 로직이 모호해집니다. 스프링은 이를 해결하기 위해 AOP를 지원합니다.

AOP는 Aspect Oriented Programming으로, 관점 지향 프로그래밍을 의미합니다. 공통 관심사를 비즈니스 로직과 분리해서 별도로 관리하는 방법입니다.

예를 들어 서비스 메서드 실행 전후에 로그를 남기거나, 특정 메서드 실행 구간을 트랜잭션으로 감싸는 작업을 매번 직접 작성하는 대신, 공통 로직을 한곳에 모아 두고 필요한 지점에 적용할 수 있습니다.

스프링의 AOP는 다음과 같은 장점이 있습니다.

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

PSA

스프링의 중요한 특징 중 하나는 트랜잭션 관리, 데이터 접근, 메시지 처리 같은 기능을 구현체별 API에 맞춰 직접 다루기보다, 일관된 방식으로 사용할 수 있게 한다는 점입니다. 이를 스프링에서는 포터블 서비스 추상화, PSA라고 표현합니다. 이러한 추상화 덕분에 애플리케이션 코드는 특정 구현체나 벤더 API에 과도하게 묶이지 않고, 구현이 바뀌더라도 변경 범위를 줄일 수 있습니다.

PSA의 장점은 다음과 같습니다.