스프링의 핵심: 의존성 역전과 객체 관리

1. 스프링 개요

1.1 소개

스프링은 소프트웨어 개발 분야에 '봄'을 선사한 프레임워크로, 기존 기술들을 통합하여 사용을 쉽게 만든다.

  • 2002년 초반, 인터페이스21 프레임워크를 기반으로 설계 시작
  • 2004년 3월 24일, 공식 버전 1.0 발표
  • 창립자: 로드 존슨 (시드니 대학교 음악학 박사, 컴퓨터 전공)
  • 핵심 철학: 기존 기술을 보다 쉽게 활용할 수 있도록 하는 것
  • 대표적인 기술 조합: SSM (Spring MVC + Spring + MyBatis), SSH (Struts + Spring + Hibernate)

1.2 장점

  • 오픈소스이자 무료로 제공되는 경량 컨테이너 프레임워크
  • 비침입적 설계, 라이브러리 종속성 최소화
  • 제어 반전(IOC)과 관심사 분리(AOP) 지원
  • 트랜잭션 처리 및 다양한 외부 프레임워크와의 원활한 통합

결론적으로, 스프링은 경량의 제어 반전(IOC)과 관심사 분리(AOP) 기반의 개발 프레임워크이다.

1.3 구성 요소

스프링은 여러 모듈로 구성되며, 주요 컴포넌트는 다음과 같다:

  • 스프링 컨텍스트 (Context): IOC 및 빈 관리 중심
  • 스프링 AOP: 가교 기능, 공통 로직 추출
  • 스프링 웹 모듈 (Web, WebMvc): 웹 애플리케이션 개발 지원
  • 스프링 데이터 (Data): 데이터 접근 계층 간편화
  • 스프링 트랜잭션: 다중 데이터베이스 트랜잭션 관리

1.4 확장 기술

현대 자바 개발의 중심은 스프링 기반의 생태계이다.

  • 스프링 부트 (Spring Boot): 빠른 설정 기반의 초기화 툴, "약속이 구성을 대체한다"는 원칙 적용
  • 스프링 클라우드 (Spring Cloud): 마이크로서비스 아키텍처를 위한 도구 모음

현재 대부분의 기업은 스프링 부트를 활용해 단일 서비스를 신속하게 개발하고 있다. 이는 스프링 및 스프링 MVC의 깊은 이해가 필수라는 의미이다.

단, 장기적인 발전 과정에서 원래의 단순성 원칙이 훼손되며, 복잡한 설정으로 인해 "설정의 지옥"이라는 비판도 존재한다.

2. IOC 이론의 도출

기존 방식에서는 클래스 간 의존성이 고정되어 있어, 변경 시 코드 수정이 필수적이었다. 이를 개선하기 위한 방법을 살펴보자.

DAO 계층 정의

package com.example.dao;

public interface UserDao {
    void fetchUser();
}

DAO 구현 클래스

package com.example.dao;

public class UserDaoMySQLImpl implements UserDao {
    @Override
    public void fetchUser() {
        System.out.println("MySQL에서 사용자 정보를 가져옵니다.");
    }
}

서비스 계층 인터페이스

package com.example.service;

public interface UserService {
    void executeUserFetch();
}

서비스 구현 클래스 (의존성 역전 적용 전후 비교)

package com.example.service;

import com.example.dao.UserDao;
import com.example.dao.UserDaoMySQLImpl;

public class UserServiceImpl implements UserService {

    // 기존 방식: 객체 생성 고정 → 유연성 없음
    // private UserDao userDao = new UserDaoMySQLImpl();

    // 개선된 방식: 외부에서 의존성 주입
    private UserDao userDao;

    // setter를 통해 동적 주입 가능
    public void setUserDao(UserDao dao) {
        this.userDao = dao;
    }

    @Override
    public void executeUserFetch() {
        userDao.fetchUser();
    }
}

새로운 데이터베이스 구현 추가

package com.example.dao;

public class UserDaoOracleImpl implements UserDao {
    @Override
    public void fetchUser() {
        System.out.println("Oracle에서 사용자 정보를 조회합니다.");
    }
}

테스트 클래스 (의존성 주입 확인)

package com.example.test;

import com.example.service.UserService;
import com.example.service.UserServiceImpl;
import com.example.dao.UserDaoOracleImpl;

public class ApplicationTest {
    public static void main(String[] args) {
        UserService service = new UserServiceImpl();
        
        // 런타임 시에 실제 구현체를 주입
        ((UserServiceImpl) service).setUserDao(new UserDaoOracleImpl());

        service.executeUserFetch(); // 출력: "Oracle에서 사용자 정보를 조회합니다."
    }
}

핵심 개념: 제어 반전 (IoC)

  • 기존 방식: 개발자가 직접 객체를 생성 → 제어권은 개발자에게 있음
  • 스프링 방식: 객체 생성을 외부(컨테이너)에 위임 → 개발자는 필요한 의존성만 정의하면 됨

이 변화는 시스템의 결합도를 크게 낮추고, 유지보수와 확장성을 극대화한다.

IoC의 본질

제어 반전은 객체 생성 및 관리의 책임을 프로그램 자체에서 외부 컨테이너로 옮기는 설계 원칙이다.

  • DI (Dependency Injection, 의존성 주입)는 IoC를 구현하는 방법 중 하나
  • XML 또는 어노테이션을 통해 빈 정의를 기술하고, 컨테이너가 빈을 생성·주입
  • 어노테이션 기반 설정 시, 구현 클래스에 빈 정보를 포함하여 완전한 자동 설정 가능

스프링에서 제어 반전은 IoC 컨테이너를 통해 이루어지며, 주로 의존성 주입 방식으로 구현된다.

태그: Spring IOC DependencyInjection SpringBoot AOP

6월 25일 22:23에 게시됨