스프링이란?
- 여러가지 기술(모듈)들의 집합
- 스프링 데이터, 스프링 세션, 스프링 시큐리티 등등
Spring Framework
- 핵심 기술 : 스프링 DI 컨테이너, AOP, 이벤트, 기타
- 웹 기술 : 스프링 MVC, 스프링 WebFlux
- 데이터 접근 기술 : 트랜잭션, JDBC, ORM 지원, XML 지원
- 기술 통합 : 캐시, 이메일, 원격접근, 스케쥴링
- 테스트 : 스프링 기반 테스트 지원
- 언어 : 코틀린, 그루비
Spring Boot
- 스프링을 편리하게 사용할 수 있도록 지원, 최근에는 기본으로 사용
- 단독으로 실행할 수 있는 스프링 어플리케이션 생성
- 톰캣 같은 웹서버를 내장하여 별도의 웹 서버를 설치하지 않아도 됨
- 손쉬운 빈드 구설을 위한 스타터 종속석 제공
- 스프링과 서드파티 외부 라이브러리 자동 구성
- 메트릭, 상태확인, 외부 구성 같은 프로덕션 준비 기능 제공
- 관례에 의한 간결한 설정
핵심 개념
- 스프링은 자바 언어 기반의 프레임워크
- 자바 언어의 가장 큰 특징 - OOP
- 스프링은 객체 지향 언어가 가진 강력한 특징을 살려내는 프레임워크
- 스프링은 좋은 객체 지향 어플리케이션을 개발할 수 있게 도와주는 프레임워크
객체지향 - 다형성의 본질
- 인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경할 수 있다.
- 다현성의 본질을 이해하려면 협력이라는 객체사이의 관계에서 시작해야함
- 클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있다.
객체지향 - 역할과 구현을 분리
- 실세계의 역할과 구현이라는 편리한 컨셉을 다형성을 통해 객체 세상으로 가져올 수 있음
- 유연하고, 변경에 용이
- 확장 가능한 설계
- 클라이언트에 영향을 주지 않는 변경 가능
- 인터페이스를 안정적으로 잘 설계하는 것이 중요
객체지향 - SOLID
SRP(Single Responesibility Principle) - 단인 책임 원칙
- 한 클래스는 하나의 책임만 가진다. 그러나 하나의 책임이라는 것을 모호한 개념
- 클 수 있고, 작을수 있음
- 문맥과 상황에 따라 다름
- 주요 기준은 변경이다. 변경이 있을때 마다 파금효과가 적으면 SRP를 잘 따른것
- 예) UI 변경, 객체의 생성과 사용을 분리
OCP(Open Closed Principle) - 개방-폐쇠 원칙
- 소프트웨어의 요소는 확장에는 열려있으나 변경에는 닫혀 있어야 한다
- 다형성을 활용하여 구현
- 인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현
- 구현 객체를 변경하려면 클라이언트 코드를 변경해야 함
- 다형성을 사용해도 완벽히 OCP 원칙을 지킬수 없음
- 객체를 생성하고, 연관관계를 맺어주는 별도의 조립, 설정하가 필요함
- 스프링의 역할
1 2 3
// 인터페이스에 구현체를 할당하는 과정에서 기존 코드의 변결이 필요해짐 InterfaceA a = new DerivedA(); // 기존코드 InterfaceA a = new DerivedAA(); // 변경코드
- 스프링의 역할
LSP(Liskov Substitution Principle) - 리스코프 치환 원칙
- 프로그램의 객체는 프로그램의 정확설을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀수 있어야 함
- 다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 한다는 것
- 다형성을 지원하기 위한 원칙
- 단순히 컴파일 성공을 넘어서는 이야기
- 예) 자동차 인터페이스의 엑셀은 앞으로 가라는 기능. 뒤로 가게 구현하면 LSP 위반.
ISP(Interface Segregation Principle) - 인터페이스 분리 원칙
- 특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스 하나보다 나음
- 자동차 인터페이스 -> 운전 인터페이스, 정비 인터페이스로 분리
- 사용자 클라리언트 -> 운전자 클라이언트, 정비사 클라이언트로 분리
- 분리하면 정비 인터페이스 자체가 변해도 운전자 클라이언트에 영향을 주지 않음
- 인터페이스가 명확해지고 대체 가능성이 높아짐
DIP(Dependecy Inversion Principle) - 의존관계 역전 원칙
- 추상화에 의존해야지, 구체화에 의존해선 안됨. 즉 구현 클래스에 의존하지 말고 인터페이스에 의존해야함
- 객체 세상도 클라이언트가 인터페이스에 의존해야 구현체를 변경할 수 있음
- 구현체에 의존하게 되면 변경이 어려워짐
- 인터페이스에 구현체를 할당하는 과정에서 구현 클래스를 의존하게됨
- 완벽히 DIP 원칙을 지킬수 없음
1 2 3
// 인터페이스에 구현체를 할당하는 과정에서 DerivedAA 라는 구현체가 필요하므로 // DerivedAA 라는 구현체에 의존하게됨 InterfaceA a = new DerivedAA();
- 완벽히 DIP 원칙을 지킬수 없음
SOLID 정리
- 객체 지향의 핵심은 다형성
- 다형성 만으로는 구현 객체를 변경 할때 클라이언트 코드도 함께 변경됨
- 다형성 만으로는 OCP, DIP를 만족 할수 없음
스프링과 객체지향
- 다형성이 중요
- 스프링은 다형성을 극대화 하여 이용할 수 있게 도와준다
- 스프링에서 이야기 하는 제어의 역전(IoC), 의존관계 주입(DI)은 다형성을 활용해서 역할과 구현을 편리하게 다룰 수 있도록 지원한다
- 스프링은 다음 기술로 다형성 + OCP, DIP를 만족할 수 있게 지원
- DI(Dependency Injection) : 의존관계, 의존성 주입
- DI 컨테이너 제공
- 클라이언트 코드의 변경없이 기능 확장
정리
- 모든 설계에 영할과 구현을 분리해야 함
- 이상적으로는 모든 설계에 인터페이스를 부여해보자
- 하지만 인터페이스를 도입하면 추상화라는 비용이 발생
- 런타임에 어떠한 구현 클레스를 사용하고 있는지 확인이 필요
- 기능을 확장할 필요가 없다면 구현 클래스를 직접 사용하고, 향후 꼭 필요할때 리펙토링을 하여 인터페이스를 도입하는 것도 하나의 방법
참고
- 스프링 핵심 원리 - 기본편(김영한)