Spring | SpringBoot

[스프링 스터디] 3주차 - 스프링 핵심 원리.기본편

saniii 2022. 1. 25. 00:49

# 참고 강의 

스프링 핵심 원리 : 김영한님

 

# 공부한 코드를 올린 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 새로운 표준 정의

 

 

# 스프링 생태계

 

<필수>

+ 스프링 프레임워크

https://ko.wikipedia.org/wiki/%EC%8A%A4%ED%94%84%EB%A7%81_%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC  

 

+ 스프링 부트

스프링을 쉽게 사용할 수 있도록 한다. 

 

 

<선택>

+ 스프링 데이터 : 기본 데이터 저장소의 특수한 특성을 유지하면서 데이터 접근을 위한 친숙하고 일관된 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을 사용하는 것이 바람직하다. 

 

 

 

다음과 같이 역할과 구현을 분리해서 자유롭게 구현 객체를 조립할 수 있게 설계하면 회원저장소과 할인 정책을 유연하게 변경할 수 있다.