[스프링 스터디] 3주차 - 스프링 핵심 원리.기본편
# 참고 강의
스프링 핵심 원리 : 김영한님
# 공부한 코드를 올린 Github
https://github.com/anso33/SpringStudy_second.git
# EJB (Enterprise Java Bean)
EJB의 비전 : EJB는 애플리케이션 개발을 쉽게 만들어준다. 애플리케이션의 개발자는 로우레벨의 기술에 관심을 가질 필요가 없다.
기업환경의 시스템을 구현하기 위한 서버 측 컴포넌트 모델
많은 동시접속자에 대한 안정성 지원
안정적인 데이터 조작
>> 동시접속자가 많은 동시에 안정적인 트랜젝션이 필요한 사이트 구축시에 사용
ex) 공공기관, 금융, 포털사이트 게임사이트, 기업 등등
지금도 그런지는 모르겠
- 문제점
객체지향적이지 않다.
프로그래밍 모델이 복잡하다.
특정 환경, 기술에 종속적인 코드
컨테이너 안에서만 동작할 수 있는 구조
개발생산성이 떨어진다.
# POJO (plain old java object)
: Java 언어 규약에 의해 강제된 것 이외의 제한에 구속되지 않는 Java 오브젝트
특정 기술과 환경에 종속되어 의존하는 자바 코드는 가독성이 떨어져 유지보수에 어려움이 생기고, 특정 기술의 클래스를 상속받거나 직접 의존하게 되어 확장성이 떨어진다. >> 객체지향 설계의 장점을 잃는다.
>> 현재는 JPA라는 표준 인터페이스 아래에서 특정 기술을 사용하도록 하여 스프링이 새로운 엔터프라이즈 기술을 도입하면서도 POJO를 유지할 수 있도록 한다.
>>> 자바의 객체지향적인 특징을 살려 비즈니스 로직에 충실한 개발이 가능하도록 한다.
# Spring
- EJB 컨테이너 대체
- 단순함의 승리
- 현재 사실상 표준 기술
- EJB없이도 충분히 고품질의 확장 가능한 애플리케이션을 개발할 수 있음
- BeanFactory, ApplicationContext, POJO, 제어의 역전, 의존관계 주입
# Hibernate
- EJB 엔티티빈 기술을 대체
- JPA 새로운 표준 정의
# 스프링 생태계
<필수>
+ 스프링 프레임워크
+ 스프링 부트
스프링을 쉽게 사용할 수 있도록 한다.
<선택>
+ 스프링 데이터 : 기본 데이터 저장소의 특수한 특성을 유지하면서 데이터 접근을 위한 친숙하고 일관된 Spring 기반의 프로그래밍 모델을 제공
+ 스프링 세션 : 특정 애플리케이션 컨테이너(예:톰캣)에 얽매이지 않고, 클러스터링된 세션을 지원하여 클라우드에서 여러 서비스들 사이에 세션 데이터의 공유를 쉽게 만들고 동일한 브라우저에서 여러 개의 세션 지원하고, 헤더에서 세션을 전송
+ 스프링 시큐리티 : 스프링 기반의 애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 스프링 하위 프레임워크
+ 스프링 Rest Docs : RESTful 서비스의 문서화를 도와주는 도구
+ 스프링 배치 : 로깅/추적, 트랜잭션 관리, 작업 처리 통계, 작업 재시작, 건너뛰기, 리소스 관리 등 대용량 레코드 처리에 필수적인 기능을 제공. 또한 최적화 및 파티셔닝 기술을 통해 대용량 및 고성능 배치 작업을 가능하게 하는 고급 기술 서비스 및 기능을 제공
+ 스프링 클라우드 : 스프링 프레임워크 환경에서 마이크로서비스아키텍처(MSA)를 구축할 수 있도록 도와주는 프로젝트. 즉, 분산환경 시스템을 구축하는데 도움을 주거나 관리할 수 있는 프로젝트들을 의미
# 스프링의 핵심은 좋은 객체 지향 애플리케이션을 만들자! 이다....
# 좋은 객체 지향 프로그래밍이란?
객체 지향 프로그래밍은 프로그램을 유연하고 변경이 용이하게 만든다. >> 대규모 소프트웨어 개발에 많이 사용.
객체지향이란 현실에 존재하는 사물을 그대로 모델링하여 그 행위와 속성을 정의하고, 객체가 중심이 되어 실제 사물이 동작하는 방식으로 설계하는 것이다. 사물에 대해서는 Object/객체 라고 부르며, 해당 사물이 하는 행위를 Method로 정의하고, 이 사물이 가지는 속성을 Variable/변수 라고 정의한다.
# 객체 지향의 특징
+ 추상화 : 모델링 / 다형성과 상속은 모두 추상화에 속한다.
+ 캡슐화 : 객체의 속성(variavle)을 보호한다.
- 추상화를 제공한다. (실제 Method가 어떻게 동작하는지 외부에서는 알 필요가 없으며 단순 호출만으로 기능을 실행할 수 있으며 즉, 객체 단위로 프로그램 설계가 가능해진다.)
+ 상속 : 하위로 내려갈수록 구체화된다.
- 재사용성이 향상된다.
- 확장성이 향상된다.
- 유지보수성이 향상된다.
+ 다형성 : 하나의 객체가 여러 개의 형태로 변화할 수 있다.
- 역할과 구현을 분리한다. >> 프로그램이 유연해지며 변경도 편리해진다.
- 클라이언트는 인터페이스만 알면 된다.
- 클라이언트는 구현 대상의 내부 구조를 몰라도 된다.
- 클라이언트는 구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다.
- 클라이언트는 구현 대상 자체를 변경해도 영향을 받지 않는다.
> 클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있다.
** 따라서 인터페이스를 안정적으로 잘 설계하는 것이 중요하다.
# SOLID (좋은 객체 지향 설계의 5가지 원칙)
+ SRP : 단일 책임 원칙(single responsibility principle)
+ OCP : 개방-폐쇄 원칙 (Open/closed principle)
+ LSP : 리스코프 치환 원칙 (Liskov substitution principle)
+ ISP : 인터페이스 분리 원칙 (Interface segregation principle)
+ DIP : 의존관계 역전 원칙 (Dependency inversion principle)
** 다형성만으로는 OCP, DIP를 지킬 수 없다. 따라서 스프링의 DI(Dependency Injection), DI 컨테이너를 통해 OCP, DIP를 실현할 수 있도록 한다.
또 날렸어 또 손가락 다시 만들고 싶다
전달 받은 요구사항에 확정되지 않은 내용이 담길 수 있다.
아직 정확한 정책이 내려오지 않았다거나, 아님 DB를 뭘 쓸지 못 정했다거나
이런 상황에서 정확한 내용이 나올 때까지 기다렸다가 개발을 할 수는 없다. 따라서 객체 지향 설계 방법을 사용하여 인터페이스를 만들고 정책이 정해지면 구현체를 언제든지 갈아끼울 수 있도록 설계하자.
실제 객체가 참조하는 방식을 다이어그램으로 나타낸 것
다이어그램을 잘 그릴 수 있어야겠다.
회원 도메인 요구사항에서 아직 DB에 대한 내용이 정해지지 않아 인터페이스를 만들고 나중에 정해진 DB에 대한 구현체로 갈아끼울 수 있도록 한다.
클라이언트는 회원서비스의 Method인 회원가입이나 로그인을 통해 회원 정보에 접근할 수 있다.
** 여기서 회원 서비스를 바로 구현체로 가져다 써서 문제인가?
그럼 회원 저장소가 바뀌었을 때 회원 서비스에 대한 내용도 변경해야하는 수고로움이 생겨서?
# 인터페이스와 구현체
//인터페이스
package hello.core.member;
public interface MemberRepository {
void save(Member member);
Member findById(Long memberId);
}
// 구현체
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
// 동시성 이슈는 고려하지 않음
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
** HashMap은 동시성 이슈가 발생할 수 있다. 따라서 HashMap보다는 ConcurrentHashMap을 사용하는 것이 바람직하다.
다음과 같이 역할과 구현을 분리해서 자유롭게 구현 객체를 조립할 수 있게 설계하면 회원저장소과 할인 정책을 유연하게 변경할 수 있다.