Group Study (2022-2023)/Spring 심화

[Spring 심화] 8주차 스터디 - 8장 스프링이란 무엇인가?

ohyujeong 2022. 12. 14. 21:27

8.1 스프링의 정의

  • 자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크
  1. 애플리케이션 프레임워크란?
    • 일반적인 라이브러리나 프레임워크, 특정 계층에서 동작하는 한 가지 기술 분야에 집중
    • ex1) 웹 계층을 MVC 구조로 손쉽게 만들 수 있게 함
    • ex2) 포맷과 출력장치 유연하게 변경가능한 애플리케이션 로그 기능 제공
    • ex3) 관계형 DB와 자바 obj 매핑해주는 ORM 기술 제공 등 
    • 애플리케이션 프레임 워크
      • 특정 계층,기술, 업무 분야에 국한 X, 애플리케이션 전 영역을 포괄하는 범용적인 프레임워크
      • 애플리케이션 전 영역을 관통하는 일관된 프로그래밍 모델과 핵심 기술을 바탕으로 각 분야의 특성에 맞는 필요를 채워주기 때문에, 애플리케이션을 빠르고 효과적으로 개발할 수 있다.
      • 스프링은 MVC 프레임워크 JDBC/ORM 프레임워크다 ? → 스프링이 다루는 일부 영역만 본 것
      • 스프링은 Ioc/DI 프레임워크, AOP 툴이다 ? → 스프링이 제공하는 핵심 기술에만 주목한 것
  2. 경량급
    • 불필요하게 무겁지 않다. → 자바 엔터프라이즈 기술의 불필요한 복잡함에 반대되는 개념
    • 가장 단순한 서버환경인 톰캣, 제티에서도 완벽하게 동작
    • 단순한 개발툴과 기본적인 개발환경으로도 엔터프라이즈 개발에서 필요로 하는 주요 기능 갖춘 애플리케이션 개발에 충분함
    • 스프링 기반 코드는 가볍다. → 프레임워크와 서버환경에 의존적인 부분 제거해주기 때문이다.
  3. 자바 엔터프라이즈 개발을 편하게
    • 개발자가 로우레벨 기술에 많은 신경을 쓰지 않으면서도, 비즈니스 로직을 빠르고 효과적으로 구현할 수 있게 함.
  4. 오픈소스
    • 소스가 모두에게 공개되고, 특별한 라이선스를 취득할 필요없이 얼마든지 가져다 자유롭게 이용 가능함
    • 스프링은 오픈소스의 장점을 취득하고 단점을 극복하며 오픈소스 방식으로 개발됨
    • 장점 : 공개된 커뮤니티 공간 안에서 투명한 방식으로 다양한 참여를 통해 개발되어서 매우 빠르고 유연한 개발이 가능하다. → 버그 발견, 기능 개선 등의 사용자 피드백이 빠르게 전달되고 반영됨
    • 단점 : 지속적이고 안정적 개발이 불확실 → 기업을 세워서 전문 개발자가 오픈소스 개발을 책임지게 하여서 단점 극복

8.2 스프링의 목적

  • 불편한 엔터프라이즈 시스템 개발을 편하게 하는 것
  • 엔터프라이즈 시스템이란? 서버에서 동작하며, 기업과 조직의 업무를 처리해주는 시스템

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

복잡함의 근본적 이유

  1. 기술적인 제약조건과 요구사항이 늘어남
    • 기업의 핵심 정보 처리, 크리티컬한 금융, 원자력, 항공, 국방 등의 시스템을 다루기도 함→ 비즈니스 로직 구현 외에도 기술적 고려사항이 많다.
    • → 보안, 안정성, 확장성 면에서도 뛰어나야함
  2. 핵심 기능인 비즈니스 로직의 복잡함 증가
    • 엔터프라이즈 시스템을 이용해 기업의 핵심 업무를 처리하는 비율 늘어남
    • 시스템이 관여하는 업무의 비율이 급증함에 따라 개발도 힘들고 복잡해져감

👉 비즈니스 로직과 엔터프라이즈 기술이라는 두 가지가 분리되지 않아서 더욱 복잡해짐

복잡함을 해결하려는 노력

  • 복잡함의 원인은 제거 대상 X, 효과적으로 상대할 수 있는 전략과 기법이 필요함
  • → 성격이 다른 두 가지 복잡함을 분리해내야함
  1. EJB - 실패한 해결책
    • 오히려 EJB라는 환경과 스펙에 종속되는 코드를 작성해야 해서 부담감이 커짐
    • EJB라는 틀 안에 자바 코드를 강제함으로써, 자바가 가지고 있던 다형성, 상속 구조 등의 장점을 잃게 됨
  2. 스프링 - 비침투적 방식을 통한 효과적 해결책
    • 비침투적 기술 : 기술의 적용사실이 코드에 직접 반영되지 않음
    • 비침투적으로 엔터프라이스 기술과 비즈니스 로직 담은 애플리케이션 코드 분리해냄

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

엔터프라이즈 기술 적용 시, 발생하는 복잡함의 문제

  1. 기술에 대한 접근 방식이 일관성이 없고, 특정 환경에 종속적이다.
    • 서버 환경, 적용 조건에 따라 코드가 바뀐다는 것은 심각한 문제이다.
    • 스프링의 해결책 : 서비스 추상화
      • 트랙잭션 추상화, OXM 추상화, 데이터 엑세스에 관한 일관된 예외변환 기능, 트랜잭션 동기화 기법 등
      • 추상화를 통해 로우레벨의 기술 구현 부분과 기술을 사용하는 인터페이스를 분리하고, 환경과 세부기술에 독립적인 접근 인터페이스를 제공함
  2. 기술적인 처리를 담당하는 코드가 성격이 다른 코드에 섞여서 등장한다.
    • 트랜잭션, 보안 적용 등의 기술 관련 코드가 비즈니스 로직에 섞여서 등장한다.
    • 스프링의 해결책 : AOP
      • 기술 관련 코드를 깔끔하게 분리해서 별도의 모듈로 관리하게 해주는 기술

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

  • 비즈니스 로직의 오류는 엄청난 사고로 이어질 수 있음
  • 엔터프라이즈 시스템 개발의 흐름은 점차 비즈니스 로직은 애플리케이션 안에서 처리하도록 만드는 추세
    • DB는 데이터의 영구적 저장, 복잡한 조건을 가진 검색과 같은 자체적으로 특화된 기능에한 활용
    • 데이터 분석, 가공, 그에 따른 로직 처리는 높은 확장성과 낮은 비용의 애플리케이션 서버로 이동

객체지향과 DI

  • DI
    • 유연하게 확장할 수 있는 오브젝트 설계를 하다 보면 자연스럽게 적용되는 객체지향 프로그래밍 기법
    • 스프링은 이것을 더욱 편하고 쉽게 사용하도록 도와줄 뿐기술적 복잡함과 분리를 위해선 DI 바탕의 여러 기법이 활용, 비즈니스 로직 자체의 복잡함 해결을 위해선 객체지향 설계 기법이 중요하다.

💡 모든 스프링의 기술과 전략은 객체지향이라는 자바 언어가 가진 강력한 도구를 극대화해서 사용할 수 있도록 돕는 것

8.3 POJO 프로그래밍

POJO란 ?

  • Plain Old Java Object
  • 자바의 단순한 오브젝트를 이용해 애플리케이션 로직을 구현하는 것

스프링의 특징과 목적

  • “스프링의 정수는 엔터프라이즈 서비스 기능을 POJO에 제공하는 것”

cf) 엔터프라이스 서비스 : 보안, 트랜잭션과 같은 엔터프라이즈 시스템에서 요구되는 기술

  • 분리됐지만 반드시 필요한 엔터프라이즈 서비스 기술을 POJO 방식으로 개발된 애플리케이션 핵심 로직을 담고 있는 코드에 제공하는 것

스프링의 핵심: POJO

  • 스프링 애플리케이션 = POJO를 이용한 애플리케이션 코드 + POJO가 어떻게 관계를 맺고 동작하는지를 정의해놓은 설계정보
  • Ioc/DI, AOP, PSA 는 애플리케이션을 POJO로 개발할 수 있게 해주는 가능기술이다.

POJO의 조건

  1. 특정 규약에 종속되지 않는다.
    • 자바 언어와 꼭 필요한 API 외에는 종속되지 않아야 한다.
    • 특정 규약 따라 만들게 하는 경우엔 대부분 규약에서 제시하는 특정 클래스를 상속하도록 요구함 → 자바의 단일 상속 제한때문에 해당 클래스에 객체지향적인 설계 기법 적용하기 어려워짐
    • 객체지향 설계의 자유로운 적용이 가능한 오브젝트여야 POJO 이다.
  2. 특정 환경에 종속되지 않는다.
    • 순수한 애플리케이션 로직을 담고 있는 오브젝트 코드가 특정 환경에 종속되게 만드는 경우엔 POJO가 아님
    • 특히, 비즈니스 로직 담은 POJO 클래스는 웹이라는 환경정보나 웹 기술을 담고 있는 클래스나 인터페이스를 사용해서는 안 됨 → 웹 외의 클라이언트가 사용하지 못하기 때문이다.
    • 소스코드에 직접 메타정보를 추가해주는 애노테이션을 사용할 경우
      • 애노테이션이 단지 코드로 표현하기에 적절치 않은 부가적 정보 담고 있고, 그 때문에 환경에 종속되지만 않는다면 POJO 라고 할 수 있음
      • 하지만, 애노테이션이나 엘리먼트 값에 특정 기술과 환경에 종속적인 정보를 담고 있다면 POJO로서의 가치 잃어버림
  3. 객체지향적인 원리에 충실해야 한다.
    • 단순히 특정 기술규약과 환경에 종속되지 않았다고 POJO인 것이 아님
    • 클래스 분리, 재사용 가능, 상속과 다형성의 활용 등 객체지향적으로 개발되어야 한다.

POJO의 장점

  • POJO가 될 수 있는 조건이 POJO의 장점이 된다.
  1. 특정 기술과 환경에 종속되지 않는 오브젝트는 깔끔한 코드가 된다.
    • 유지보수에 유리하다.
    • 자동화 테스트에 유리하다.
  2. 객체지향적인 설계를 자유롭게 적용할 수 있다.
    • 도메인 모델, 재활용 가능한 설계모델인 디자인 패턴 등은 POJO가 아니고는 적용하기 힘듦

POJO 프레임워크

  • 하이버네이트
    • DB 이용 기술에 POJO를 적용
  • 스프링
    • 애플리케이션 개발의 모든 영역과 계층에서 POJO 방식의 구현이 가능

  • 스프링은 비즈니스 로직의 복잡함과 엔터프라이 기술의 복잡함을 분리해서 구성할 수 있게 도와줌
  • 자신은 기술영역에 관여할 뿐, 비즈니스 로직을 담당하는 POJO에서는 모습을 감춤
  • 데이터 엑세스 로직, 웹 UI 로직 등을 다룰 때만 최소한의 방법으로 관여
  • POJO 프레임워크로서 스프링은, 자신을 직접 노출하지 않으면서 애플리케이션을 POJO로 쉽게 개발할 수 있게 지원해준다.

8.4 스프링의 기술

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

  • 왜 두개의 오브젝트를 분리하고 인터페이스를 두고 느슨하게 연결한 뒤, 실제 사용할 대상은 DI를 통해 외부에서 지정하는가? → 유연한 확장을 가능하게 하기 위해서
  • OCP (개방 폐쇄 원칙) 으로 설명할 수 있다.
    • 확장에는 열려 있고, 변경에는 닫혀 있다.

ex) A→B의 의존관계 갖는 오브젝트 구조

  • 확장은 B가 자유롭게 변경될 수 있음을 의미 → A는 영향 받지 않고 유지
  • B 입장 : 유연한 확장
  • A 입장 : 변경없이 재사용 가능

DI의 활용 방법

  • 핵심기능의 변경
    • DI 의 가장 대표적인 적용 방법 : 의존 대상의 구현을 바꾸는 것
    • 필요에 따라 B의 구현 방식을 통째로 B1,B2,B3 로 바꿈ex) 서비스 오브젝트가 사용하는 DAO 구현을 JDBC, JPA, 하이버네이트 등으로 변경
  • 핵심기능의 동적인 변경
    • 의존 오브젝트의 핵심 기능 자체를 바꾸는 것
    • 애플리케이션 동작 중간에 의존대상을 다이내믹하게 변경함
    • 다이내믹 라우팅 프록시, 프록시 오브젝트 기법 등 활용
  • 부가기능의 추가
    • 핵심 기능 그대로 둔 채 부가기능을 추가 → 데코레이터 패턴 적용
    ex) 트랜잭션 기능 부여
    • 부가기능 추가를 특정 오브젝트가 아니라 좀 더 많은 대상으로 일반화해서 적용하면 AOP가 됨
  • 인터페이스의 변경
    • 클라이언트가 사용하는 인터페이스와 실제 오브젝트 사이에 인터페이스가 일치하지 않는 경우가 있을 때 DI를 사용하여 해결할 수 있다.
    ex)

(상황) A가 C 오브젝트 사용하려 할 때, A는 B 인터페이스 사용하도록 만들어져 있고 C는 B 인터 페이스 구현 안 함
(해결) A가 B DI를 통해 B의 구현 오브젝트 받도록 만들어져 있다면, B 인터페이스를 구현했으면서 내부에서 C를 호출해주는 기능을 가진 어댑터 오브젝트를 만들어 A에 DI 해주면 된다.

(결론)A→B(C로 위임)→C로 구성

→ 위의 예시를 일반화해서 아예 인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록, 중간에 인터페이스 어댑터 역할을 해주는 레이어를 하나 추가하는 방법도 있음 = 서비스 추상화(PSA)

PSA는 클라이언트가 일관성 있게 사용할 수 있는 인터페이스를 정의해주고 DI를 통해 어댑터 역할을 하는 오브젝트를 이용하게 해준다. 

  • 프록시
    • lazy loading(지연된 로딩) : 필요한 시점에 실제 사용할 오브젝트를 초기화하고 리소르를 준비해줌
    • 원격 오브젝트를 호출 할 때 마치 로컬에 존재하는 오브젝트처럼 사용할 수 있게 해주는 원격 프록시 적용할 때→ 두 개 모두 프록시 필요, 프록시는 DI를 필요로 함
  • 템플릿과 콜백
    • DI의 특별한 적용 방법
    • 반복적으로 등장하지만 항상 고정적인 작업 흐름과 그 사이에서 자주 바뀌는 부분을 분리해서 템플릿과 콜백으로 만들고 이를 DI 원리를 응용해서 적용한다.
    • 콜백을 얼마든지 만들어서 사용할 수 있다. → 개방을 통한 유연학 확장성
    • 템플릿은 한 번 만들어두면 계속 재사용할 수 있다. → 기능의 확장에도 변하지 않는다는 OCP의 폐쇄 원칙
  • 싱글톤과 오브젝트 스코프
    • DI 할 오브젝트의 생명주기를 제어함
    • DI 를 프레임워크로 이용한다는 것
      • DI 대상 오브젝트를 컨테이너가 관리한다는 의미
      • 오브젝트 생성, 관계 설정, 이용, 소멸까지 모든 과정을 DI 컨테이너가 주관하기 때문에 오브젝트의 스코프를 자유롭게 제어할 수 있다.
    • 싱글톤
      • 스프링의 DI는 기본적으로 싱글톤으로 오브젝트를 만들어서 사용함
      • 컨테이너가 알아서 싱글톤을 만들고 관리하기 때문에 클래스 자체는 싱글톤을 고려하지 않고 자유롭게 설계해도 된다.
  • 테스트
    • 의존 오브젝트를 스텁, 목 오브젝트와 같은 테스트 대역을 활용해서 간단하게 만듦
    • DI를 활용해서 테스트 코드 안에 수동으로 목 오브젝트 주입 가능, 테스트용 설정 별도로 만들기 가능

애스펙트 지향 프로그래밍 (AOP)

  • 객체지향 기술의 한계와 단점을 극복하도록 도와주는 보조적인 프로그래밍 기술
  • IoC/DI를 이용해서 POJO에 선언적인 엔터프라이즈 서비스 제공할 수 있지만, 일부 서비스는 순수한 객체지향 기법만으로는 POJO의 조건을 유지한 채 적용하기 힘듦 → AOP 이용해서 해결한다.

AOP의 적용 기법

  1. 다이내믹 프록시 사용
    • 기존 코드에 영향 X, 부가기능 적용하게 해주는 데코레이터 패턴 응용한 것
    • 부가기능 부여할 수 있는 곳이 메소드 호출이 일어나는 지점뿐이라는 제약이 있다.
    • 스프링의 기본적인 AOP 구현 방법은 다이내믹 프록시 방법
  2. 자바 언어의 한계를 넘어서는 언어의 확장 이용
    • AspectJ 사용
      • 프록시 방식의 AOP에서는 불가능한 다양한 조인포인트 제

AOP의 적용 단계

AOP는 하나의 모듈이 수많은 오브젝트에 보이지 않게 적용되기 때문에 익숙하지 않다면, 차근차근 도입해야 한다.

  1. 미리 준비된 AOP 이용
    • 스프링이 미리 만들어서 제공하는 AOP 기능을 그대로 적용
    • 트랜잭션, @Configurable
  2. 전담팀 통한 정책 AOP 이용
    • 애플리케이션 전체적으로 이용 가능한 것을 소수의 AOP 담당자 관리하에 적용
    • 비즈니스 로직 가진 오브젝트에 대한 보안, 특정 계층의 오브젝트 이용 전후의 작업 기록을 남기는 로깅, 데이터 추적을 위한 트레이싱, 특정 구간의 실시간 성능 모니터링과 같은 정책적으로 적용할 만한 기능에 AOP 이용
  3. AOP의 자유로운 이용
    • 개발자가 구현하는 기능에 적용하면 유용한 세부적인 AOP 이용

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

  • 환경과 세부 기술의 변화에 관계 없이 일관된 방식으로 기술에 접근할 수 있게 해주는 기술
  • 특정 환경과 기술에 종속적이지 않다는 것은, 그런 기술을 사용하지 않는다는 뜻 X → POJO 코드가 그런 기술에 직접 노출되어 만들어지지 않는 것 → 이를 위해 제공하는 기술이 PSA
  • PSA는 AOP나 템플릿/콜백 패턴과 결합돼서 사용되는 경우가 있다. 이럴 때는 직접적으로 이용할 필요가 없다. 대신 설정을 통해 어떤 종류의 기술을 사용할 지 지정해줘야 한다.
  • 서비스 추상화는 테스트가 어렵게 만들어진 API나 설정을 통해 주요 기능을 외부에서 제어하고 만들고 싶을 때도 이용할 수 있다.

8.5 정리

  • 스프링은 그 개발철학과 목표를 분명히 이해하고 사용해야 한다.
  • 스프링은 오픈소스 소프트웨어이며, 애플리케이션 개발의 모든 기술과 영역을 종합적으로 다루는 애플리케이션 프레임워크다.
  • 엔터프라이즈 애플리케이션 개발의 복잡함은 비즈니스 로직과 엔터프라이즈 시스템의 기술적인 요구에 의해 발생한다. 기존의 접근 방법은 이 복잡도를 낮추지 못하며 자바의 객체지향적인 장점을 포기해야 한다는 문제점이 있다.
  • 자바의 근본인 객체지향적인 원리에 충실하게 개발할 수 있으며, 환경과 규약에 의존적이지 않은 POJO를 이용한 애플리케이션 개발은 엔터프라이즈 시스템 개발의 복잡함이 주는 많은 문제를 해결할 수 있다.
  • 스프링의 목적은 이런 POJO를 이용해 엔터프라이즈 애플리케이션을 쉽고 효과적으로 개발할 수 있도록 지원해주는 데 있다.
  • POJO 방식의 개발을 돕기 위해 스프링은 IoC/DI, AOP, PSA와 같은 가능기술을 프레임워크와 컨테이너라는 방식을 통해 제공한다.