[Spring] Spring의 탄생 배경과 핵심 개념

19·2022년 9월 7일
0

Spring

목록 보기
13/29

Spring 탄생 전에는 EJB라는 기술을 사용했었다

EJB의 문제점

  • 너무 복잡하고 느림
  • EJB가 지원하는 인터페이스 구현해야 함 -> EJB에 종속적
    • 코드가 지저분해짐

EJB를 사용하면 EJB에 의존적으로 코드를 작성해야 하기 때문에, POJO라는 개념이 등장

  • 순수하게 옛날 자바로 돌아가자
  • 옛날에 사용하던 자바 오브젝트를 사용하자

EJB를 대체하기 위해 Spring이 탄생
EJB 엔티티빈을 대체하기 위해 Hibernate가 탄생 (JPA 구현체가 Hibernate)

  • Hibernate를 자바표준으로 만든것이 JPA

Spring Framework

  • 핵심기술: DI 컨테이너, AOP등
  • 웹 기술: 스프링 MVC등
  • 데이터 접근 기술: 트랜잭션, ORM 지원등
  • 기술 통합: 캐시, 원격접근등
  • 테스트: 스프링 기반 테스트 지원
    등으로 구성되어 있고, 이를 편리하게 사용하기 위해 Spring Boot가 등장

Spring Boot

스프링을 편리하게 사용할 수 있도록 지원

  • Tomcat같은 웹 서버를 내장해서 별도의 웹 서버를 설치하지 않아도 된다
    • 이전에는 Tomcat을 설치하고, Tomcat의 특정 위치에 빌드한 스프링 프로젝트를 넣어야 했다.
  • starter 종속성 제공
  • 스프링과 3rd party(외부) 라이브러리 자동 구성
    • 스프링 프레임워크과 외부 라이브러리 버전을 알아서 지정해주고 다운로드

Spring을 만든 이유?

핵심 개념!

스프링은 자바 언어 기반의 프레임워크이다.
자바의 가장 큰 특징은 객체지향 언어!
스프링은 객체 지향 언어가 가진 특징을 살려내는 프레임워크이고, 좋은 객체지향 어플리케이션을 개발할 수 있게 도와주는 프레임워크이다

기존에 EJB를 사용할 때는 EJB를 상속받는 등 EJB에 의존적으로 개발했었다.
이렇게 되면 객체지향의 장점을 잃어버리게 되고 EJB 종속되버리게 된다.
그래서 POJO라는 단어가 등장하고 예전의 자바 스타일로 돌아가자는 움직임이 생겼다.
핵심은 객체지향

객체지향 특징

  • 추상화
  • 캡슐화
  • 상속
  • 다형성

객체지향 프로그래밍

프로그램을 유연하고 변경이 용이하게 만든다.

유연하고 변경에 용이하다

  • 컴포넌트를 쉽고 유연하게 변경하면서 개발할 수 있는 방법
    • 레고 블록 조립하듯
    • 컴퓨터 부품 변경하듯

-> 다형성

다형성

  • 역할과 구현으로 세상을 구분

  • 자동차 역할을 K3, 아반떼, 테슬라 모델3로 구현
  • K3를 타다가 아반떼로 자동차를 변경해도 운전자는 운전을 할 수 있다.
    • 운전자는 어떤 자동차인지 여부는 상관없고 자동차가 변경되어도 영향을 미치지 않는다 (운전 가능)
    • K3, 아반떼, 테슬라 모델3는 자동차 역할(인터페이스를) 구현한 것이다.
  • 운전자는 특정 자동차 구현체에 종속적이지 않고, 자동차 역할(인터페이스)에 의존
  • 자동차 구현체에 변경이 일어나도, 자동차 역할만 준수하면 운전자에게 어떠한 영향도 미치지 않음
    • 자동차 역할만 준수하면 자동차 세상을 무한히 확장 가능
      • 클라이언트에 영향을 미치지않고 새로운 기능을 추가할 수 있다.

  • 로미오 역할을 맡은 사람은 줄리엣 역할을 누가 맡는지 중요하지 않다.

클라이언트에 영향을 주지 않고 새로운 기능을 제공할 수 있다.
새로운 구현체가 나와도, 클라이언트에서 수정할 필요가 없다.
클라이언트는 대상의 역할(인터페이스)만 알면 된다. (내부 구조 몰라도 ok, 내부 구조 변경되어도 영향 x)
클라이언트는 구현 대상 자체가 변경되어도 영향을 받지 않는다.

자바의 다형성이 위의 개념을 구현했다.
역할 = 인터페이스
구현 = 인터페이스를 구현한 클래스

객체 설계 시, 역할과 구현을 정확히 분리해야 한다. -> 객체 간 협력 관계를 그대로 재사용할 수 있다!


다형성의 본질

인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경할 수 있다.
다형성의 본질을 이해하려면 협력이라는 객체사이의 관계에서 시작해야 한다
클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있다.

  • MemberService(클라이언트는) MemberRepository(역할)를 의존하고 있다.
public class MemberService {
    private MemberRepository memberRepository = new MemoryMemberRepository();
}
public class MemberService {
    // private MemberRepository memberRepository = new MemoryMemberRepository();
    private MemberRepository memberRepository = new JdbcMemberRepository();
}

Spring과 객체지향

  • Spring은 다형성을 극대화해서 이용할 수 있게 도와준다
  • Spring에서 제어의역전(IoC), 의존곤계 주입(DI)은 다형성을 활용해서 역할과 구현을 편리하게 다룰 수 있도록 지원한다
  • Spring을 사용하면 역할의 구현체를 편리하게 변경할 수 있다.
    • 자동차를 바꾸듯이

SOLID

  • SRP: 단일 책임 원칙 (Single Responsibility Pricinple)
  • OCP: 개방-폐쇄 원칙 (Open/Closed Pricinple)
  • LSP: 리스코프 치환 원칙 (Liskov Substitution Pricinple)
  • ISP: 인터페이스 분리 원칙 (Interface Segregation Pricinple)
  • DIP: 의존관계 역전 원칙 (Dependency Inversion Pricinple)

SRP 단일 책임 원칙

한 클래스는 하나의 책임만 가져야 한다.
중요한 기준은 변경이며, 변경 시 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것
EX) 객체의 생성과 사용 분리

OCP 개방-폐쇄 원칙

소프트웨어 요소는 확장에는 열려있으나, 변경에는 닫혀있어야 한다.
다형성을 활용해 준수할 수 있음

public class MemberService {
    // private MemberRepository memberRepository = new MemoryMemberRepository();
    private MemberRepository memberRepository = new JdbcMemberRepository();
}
  • 구현 객체 변경하려면 클라이언트 코드를 변경해야 한다
  • 다형성을 활용했지만 OCP 원칙 위반

이를 해결하기 위해 객체를 생성하고, 연관관계를 맺어주는 별도의 설정자가 필요하다
-> 스프링 컨테이너가 해줌 (DI)

LSP 리스코프 치환 원칙

상위 타입의 객체를 하위 타입의 객체로 치환해도 동작에 문제가 없어야 한다.
EX) 자동차 인터페이스의 엑셀을 앞으로 가라는 기능인데, 이를 하위에서 뒤로 가게 구현하면 LSP 위반

ISP 인터페이스 분리 원칙

클라이언트 입장에서 사용하는 기능만 제공하도록 인터페이스를 분리해야 한다.
특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
인터페이스를 분리하게 되면 인터페이스가 명확해진다
EX) 자동차 인터페이스 -> 운전 인터페이스, 정비 인터페이스로 분리
-> 정비 인터페이스에 변동이 있어도 운전자 클라이언트에 영향을 주지 않는다

DIP 의존관계 역전 원칙

구체화에 의존하지 말고 추상화에 의존해야 한다.
구현이 아닌 역할에 의존해야 한다.
구현(구현 클래스)에 의존하면 변경이 어려워지기 때문!
역할(인터페이스)에 의존해야 유연하게 변경할 수 있다.

public class MemberService {
    // private MemberRepository memberRepository = new MemoryMemberRepository();
    private MemberRepository memberRepository = new JdbcMemberRepository();
}
  • 인터페이스를 의존하지만, new를 통해 구현 클래스도 의존함
    • 클라이언트(MemberService)가 구현 클래스를 직접 선택
    • DIP 위반

객체지향의 핵심은 다형성!
다형성만으로 유연하고 변경이 용이하게 개발할 수 없다.
구현 클래스를 변경할 때 클라이언트 코드 변경 (OCP 위반)
인터페이스에 의존하지만 구현 클래스에도 의존 (DIP 위반)
다형성만으로는 OCP, DIP를 준수할 수 없다

-> 이러한 문제를 스프링에서 해결했다. (DI 사용)


Spring은 어떻게 OCP, DIP를 준수할까?

Spring은 DI(Dependency Injection)을 사용해 다형성 + OCP,DIP를 가능하게 지원한다.
DI를 통해 클라이언트 코드의 변경없이 기능을 확장하고, 부품을 교체하듯 쉽게 개발할 수 있도록 해준다.

profile
하나씩 차근차근

0개의 댓글