백엔드/프레임워크

[토비의 스프링] 1장: 오브젝트와 의존관계

박지환 2023. 1. 14. 19:59
토비의 스프링: Vol. 1: 스프링의 이해와 원리

스프링의 핵심 철학

자바 엔터프라이즈 기술의 혼란 속에서 잃어버렸던 객체지향 기술의 진정한 가치를 회복시키고, 그로부터 객체지향 프로그래밍(Object Oriented Programming)이 제공하는 폭넓은 혜택을 누릴 수 있도록 기본으로 돌아가자는 것이 스프링의 핵심 철학

스프링의 관심사

오브젝트(Object) → 객체지향 설계, 디자인 패턴, 리팩토링, 단위 테스트와 같은 오브젝트 설계와 구현에 관한 기술과 지식이 요구됨

자바빈(JavaBean): 디폴드 생성자 (파라미터가 없는 생성자)와 프로퍼티 (set, get을 가진 오브젝트가 노출하는 속성)를 가진 오브젝트

리팩토링(Refactoring): 기존의 코드를 외부의 동작방식에는 변화 없이 내부 구조를 개선하는 작업

스프링에 사용된 디자인 패턴

소프트웨어 설계 시 득정 상황에서 자주 만나는 문제를 해결하기 위해 사용할 수 있는 재사용 가능한 솔루션

템플릿 메소드 패턴: 상속을 통해 슈퍼클래스의 기능을 확장할 떄 사용하는 대표적인 방법, 변하지 않는 기능은 슈퍼클래스에 만들어주고 자주 변경되며 확장할 기능은 서브클래스에서 만들도록 하는 패턴

팩토리 메소드 패턴: 상속을 통해 기능을 확장하는 패턴, 서브클래스에서 오브젝트 생성 방법과 클래스를 결정할 수 있도록 미리 정의해둔 메소드를 팩토리 메소드라고 하고, 이 방식을 통해 오브젝트 생성 방법을 나머지 로직, 즉 슈퍼클래스의 기본 코드에서 독립시키는 패턴

스프링에서의 객체지향의 원칙과 패턴

개방 폐쇄 원칙(OCP, Open-Closed Principle): 클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다

객체지향 설계 원칙(SOLID)

  • SRP(The Single Responsibility Principle, 단일 책임 원칙): 한 클래스는 하나의 책임만 가져야 한다
  • OCP(The Open Closed Principle, 개방 폐쇄 원칙): 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다
  • LSP(The Liskov Subsistuation Principle, 리스코프 치환 원칙): 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다
  • ISP(The Interface Segregation Principle, 인터페이스 분리 원칙): 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다
  • DIP(The Dependency Inversion Principle, 의존관계 역전 원칙): 프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안된다

높은 응집도와 낮은 결합도

높은 응집도: 하나의 모듈, 클래스가 하나의 책임 또는 관심사에만 집중되어 있음

낮은 결합도: 책임과 관심사가 다른 오브젝트 또는 모듈과는 낮은 결합도, 즉 느슨하게 연결된 형태를 유지하는 것이 바람직함

전략 패턴

전략 패턴: 자신의 기능 맥락(context)에서, 필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 통째로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있게 하는 디자인 패턴

팩토리(factory): 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려주는 오브젝트

제어의 역전

제어의 역전(IoC: Inversion of Control): 제어 권한을 자신이 아닌, 다른 대상에게 위임하는 방식

  • 라이브러리: 애플리케이션 코드가 애플리케이션 흐름을 직접 제어
  • 프레임워크: 프레임워크가 흐름을 주도하는 중에 개발자가 만든 애플리케이션 코드를 사용함

스프링의 IoC

스프링의 핵심을 담당하는 것: 빈 팩토리 = 애플리케이션 컨텍스트

빈(bean): 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트

빈 팩토리(bean factory): 빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트

애플리케이션 컨텍스트(application context) = 스프링 컨테이너: 애플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 담당하는 IoC 엔진, 보통 빈 팩토리를 애플리케이션 컨텍스트로 확장하여 사용함

어노테이션

  • @Configuration: 애플리케이션 컨텍스트 또는 빈 팩토리가 사용할 설정정보라는 표시
  • @Bean: 오브젝트 생성을 담당하는 IoC용 메소드라는 표시

스프링 IoC의 용어 정리

  • 빈(bean): 스프링이 IoC 방식으로 관리하는 오브젝트
  • 빈 팩토리(bean factory): 스프링의 IoC를 담당하는 핵심 컨테이너
  • 애플리케이션 컨텍스트(application context): 빈 팩토리를 확장한 IoC 컨테이너
  • 설정정보/설정 메타정보(configuration metadata): 애플리케이션 컨텍스트 또는 빈 팩토리가 IoC를 적용하기 위해 사용하는 메타정보
  • 컨테이너/IoC 컨테이너(container): IoC 방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트나 빈 팩토리를 컨테이너 또는 IoC 컨테이너라고 지칭
  • 스프링 프레임워크: IoC 컨테이너, 애플리케이션 컨텍스트를 포함해서 스프링이 제공하는 모든 기능을 통틀어 말할 때 사용하는 용어

애플리케이션 컨텍스트

애플리케이션 컨텍스트는 싱글톤을 저장하고 관리하는 싱글톤 레지스트리(singleton registry)이다

싱글톤 패턴(Singleton Pattern): 어떤 클래스를 애플리케이션 내에서 제한된 인스턴스 개수, 이름처럼 주로 하나만 존재하도록 강제하는 패턴

서비스 오브젝트: 서버의 부하를 줄이기 위해 빈, 오브젝트를 싱글톤으로 만듬, 서버환경에서는 서버스 싱글톤의 사용이 권장됨.

스프링은 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공함 → 싱글톤 레지스트리

스프링 빈의 스코프: 컨테이너 내에 한 개의 오브젝트만 만들어져서, 스프링 컨테이너가 존재하는 동안 계속 유지됨

의존관계 주입

의존관계 주입(DI: Dependency Injection): 스프링 IoC 기능의 대표적인 동작원리

의존관계 주입(DI: Dependency Injection): 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 다이나믹하게 주입

의존관계 주입의 핵심: 설계 시점에는 알지 못했던 두 오브젝트의 관계를 맺도록 도와주는 제3의 존재가 있음

DI는 자신이 사용할 오브젝트에 대한 선택과 생성 제어권을 외부로 넘기고 자신은 수동적으로 주입받은 오브젝트를 사용함

의존관계 검색(DL: Dependency Lookup): 자신이 필요로 하는 의존 오브젝트를 능동적으로 찾음

정리

스프링이 제공하는 1번째 핵심 가치: 객체지향

이를 실현하는 스프링의 핵심 기술: IoC/DI

DAO 코드의 개선

  1. 책임이 다른 코드를 분리해서 두 개의 클래스로 만듬 → 관심사의 분리, 리팩토링
  2. 바뀔 수 있는 쪽의 클래스는 인터페이스를 구현하도록 하고, 다른 클래스에서는 인터페이스를 통해서만 접근하도록 만듬, 이렇게 하면 인터페이스를 정의한 쪽의 구현 방법이 달라져 클래스가 바뀌더라도, 그 기능을 사용하는 클래스의 코드는 같이 수정할 필요가 없도록 만듬 → 전략 패턴
  3. 이를 통해 자신의 책임 자체가 변경되는 경우 외에는 불필요한 변화가 발생하지 않도록 막아주고, 자신이 사용하는 외부 오브젝트의 기능은 자유롭게 확장하거나 변경할 수 있게 만듬 → 개방 폐쇄 원칙
  4. 결국 한쪽의 기능 변화가 다른 쪽의 변경을 요구하지 않아도 되게 했고 → 낮은 결합도, 자신의 책임과 관심사에만 순수하게 집중하는 깔끔한 코드가 만들어짐→ 높은 응집도
  5. 오브젝트가 생성되고 여타 오브젝트와 관계를 맺는 작업의 제어권을 별도의 오브젝트 팩토리를 만들어 넘김. 또는 오브젝트 팩토리의 기능을 일반화한 IoC 컨테이너로 넘겨서 오브젝트가 자신이 사용할 대상의 생성이나 선택에 관한 책임으로부터 자유롭게 만들어졌음 → 제어의 역전/IoC
  6. 서버에서 사용되는 서비스 오브젝트로서의 장점을 살릴 수 있는 싱글톤을 사용하면서도 싱글톤 패턴의 단점을 극복할 수 있도록 설계된 컨테이너를 사용함 → 싱글톤 레지스트리
  7. 설계 시점과 코드에는 클래스와 인터페이스 사이의 느슨한 의존관계만 만들어놓고, 런타임 시에 실제 사용할 구체적인 의존 오브젝트를 제3자(DI 컨테이너)의 도움으로 주입받아서 다이내믹한 의존관계를 갖게 해줌 → 의존관계 주입/DI
  8. 의존 오브젝트를 주입할 때 생성자를 이용하는 방법과 수정자 메소드를 이용하는 방법 → 생성자 주입과 수정자 주입
  9. XML를 이용해 DI 설정정보를 만들고 의존 오브젝트가 아닌 일반 값을 외부에서 설정해서 런타임 시에 주입하는 방법 → XML 설정

스프링이란?