Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8주차](권용현, 임주민, 이세원) #12

Open
sunwootest opened this issue Aug 14, 2023 · 3 comments
Open

[8주차](권용현, 임주민, 이세원) #12

sunwootest opened this issue Aug 14, 2023 · 3 comments
Assignees
Labels

Comments

@sunwootest
Copy link
Collaborator

  • 8주차
    • 7.5 ~ 7.7장
    • 8장
    • 9장
@kwonyonghyun
Copy link

kwonyonghyun commented Aug 21, 2023

스프링이란 무엇인가?

스프링에 대해 가장 잘 알려진 정의는 다음과 같다.

자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크

  • 애플리케이션 프레임워크

애플리케이션 프레임워크는 애플리케이션 개발의 전 과정을 빠르고 편리하며 효율적으로 진행하는 것을 목표로 가진, 특정 계층이나 기술, 업무 분야에 국한되지 않고 애플리케이션의 전 영역을 포괄하는 범용적인 프레임워크를 말한다.
단지 여러 계층의 다양한 기술을 한데 모아뒀기 때문이 아닌, 애플리케이션 전 영역을 관통하는 일관된 프로그래밍 모델과 핵심 기술을 바탕으로 해서 각 분야의 특성에 맞는 필요를 채워주고 있기 때문에 애플리케이션 프레임워크라고 불리는 것이다.

  • 경량급

스프링이 가볍다고 하는 이유는 불필요하게 무겁지 않다는 의미다. 이러한 표현은 예전의 EJB 같은 과도한 엔지니어링이 적용된 기술과 스프링을 대비시켜 설명하려고 사용했던 표현이다.
단순한 개발툴과 기본적인 개발환경으로도 엔터프라이즈 개발에서 필요로 하는 주요한 기능을 갖춘 애플리케이션을 개발하기에 충분하다. 스프링의 장점은 그런 가볍고 단순한 환경에서도 복잡한 EJB와 고가의 WAS를 갖춰야만 가능했던 엔터프라이즈 개발의 고급 기술을 대부분 사용할 수 있다는 점이다.
결과적으로 스프링은 EJB를 대표로 하는 기존의 많은 기술이 불필요하게 무겁고 복잡했음을 증명한 셈이고, 그런 면에서 스프링은 군더더기 없이 깔끔한 기술을 가진 경량급 프레임워크라고 불린 것이다.
만들어진 코드가 지원하는 기술수준은 비슷하더라도 그것을 훨씬 빠르고 간편하게 작성하게 해줌으로써 생산성과 품질 면에서 유리하다는 것이 경량급이라는 말로 표현되는 스프링의 특성이다

  • 자바 엔터프라이즈 개발을 편하게

스프링은 근본적인 부분에서 엔터프라이즈 개발의 복잡함을 제거해내고 진정으로 개발을 편하게 해주는 해결책을 제시한다.
여기서 말하는 편리한 애플리케이션 개발이란 개발자가 복잡하고 실수하기 쉬운 로우레벨 기술에 많은 신경을 쓰지 않으면서 애플리케이션의 핵심 사용자의 요구사항, 즉 비즈니스 로직을 빠르고 효과적으로 구현하는 것을 말한다.

  • 오픈소스

여러가지 장점을 가지고 있는 것이 오픈소스 방식이지만 언제 지원이 중단될지 알 수 없다는 단점이 있습니다.
이런 단점을 극복하기 위해 전문기업을 만들었다.

스프링의 목적

엔터프라이즈 개발이 복잡한 이유?

  • 기술적인 제약조건과 요구사항이 늘어가기 때문이다.
  • 엔터프라이즈 애플리케이션이 구현해야 할 핵심기능인 비즈니스 로직의 복잡함이 증가하기 때문이다.

전통적인 자바 엔터프라이즈 개발 기법은 대부분 비즈니스 로직의 복잡한 구현 코드와 엔터프라이즈 서비스를 이용하는 기술적인 코드가 자꾸 혼재될 수 밖에 없는 방식이었다. 결국 개발자가 동시에 그 두 가지를 모두 신경 써서 개발해야 하는 과도한 부담을 줬고, 그에 따라 전체적인 복잡함은 몇 배로 가중됐다.

복잡함을 해결하려는 도전

  • 기술적 복잡함을 상대하는 전략

기술적인 복잡함을 분리해서 생각하면 그것을 효과적으로 상대할 수 있는 전략을 발견할 수 있다. 스프링은 엔터프라이즈 기술을 적용했을 때 발생하는 복잡함의 문제를 두 가지로 분류하고 각각에 대한 적절한 대응 방법을 제공한다.

첫번째 문제: 기술에 대한 접근 방식이 일관성이 없고, 특정 환경에 종속적이다.

서비스 추상화를 이용. 기술적인 복잡함은 일단 추상화를 통해 로우레벨의 기술 구현 부분과 기술을 사용하는 인터페이스를 분리하고, 환경과 세부기술에 독립적인 접근 인터페이스를 제공하는 것이 가장 좋은 해결책이다.

두번째 문제: 기술적인 처리를 담당하는 코드가 성격이 다른 코드에 섞여서 등장한다.

AOP 이용. AOP는 최후까지 애플리케이션 로직을 담당하는 코드에 남아 있는 기술 관련 코드를 깔끔하게 분리해서 별도의 모듈로 관리하게 해주는 강력한 기술이다.

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

지금까지 보았듯이 기술적인 복잡함을 효과적으로 다루게 해주는 기법은 모두 DI를 바탕으로 하고 있다. 그리고 DI는 객체지향 설계 기술 없이는 그 존재의미가 없다. 스프링은 단지 그것을 더욱 편하고 쉽게 사용하도록 도와줄 뿐이다.

POJO 프로그래밍

스프링 핵심 개발자들은 "스프링의 정수"는 "엔프라이즈 서비스 기능을 POJO 에 제공하는 것"이라고 했다. 엔터프라이즈 서비스라고 하는 것은 보안, 트랜잭션과 같은 엔터프라이즈 시스템에서 요구되는 기술을 말한다. 이런 기술을 POJO에 제공한다는 말은, 뒤집어 생각해보면 엔터프라이즈 서비스 기술과 POJO라는 애플리케이션 로직을 담은 코드를 분리했다는 뜻이기도 하다. '분리됐지만 반드시 필요한 엔터프라이즈 서비스 기술을 POJO 방식으로 개발된 애플리케이션 핵심 로직을 담은 코드에 제공한다'는 것이 스프링의 가장 강력한 특징과 목표다.

스프링의 핵심: POJO

스프링 애플리케이션은 POJO를 이용해서 만든 애플리케이션 코드와, POJO 가 어떻게 관계를 맺고 동작하는지를 정의해놓은 설계정보로 구분된다. DI의 기본 아이디어는 유연하게 확장 가능한 오브젝트를 만들어두고 그 관계는 외부에서 다이내믹하게 설정해준다는 것이다.

스프링의 주요 기술인 IoC/DI, AOP, 서비스 추상화는 애플리케이션을 POJO로 개발할 수 있게 해주는 가능기술이라고 불린다.

POJO의 조건

  • 특정 규약에 종속되지 않는다
    POJO는 자바 언어와 꼭 필요한 API 외에는 종속되지 않아야 한다. 특정 규약을 따라 만들게 하는 경우는 대부분 규약에서 제시하는 특정 클래스를 상속하도록 요구한다. 그런 경우에단일 상속 제한 때문에 더 이상 해당 클래스에 객체지향적인 설계 기법을 적용하기가 어려워진다는 문제가 생긴다. 또한 규약이 적용된 환경에 종속적이 되기 때문에 다른 환경으로 이전이 힘들다는 문제점이 있다.
  • 특정 환경에 종속되지 않는다.
    POJO는 환경에 독립적이어야 한다.특히 비즈니스 로직을 담고 있는 POJO 클래스는 웹이라는 환경정보나 웹 기술을 담고 있는 클래스나 인터페이스를 사용해서는 안된다.
    단지 자바의 문법을 지키고 순수하게 JavaSE API만을 사용했다고 해서 그 코드를 POJO라고 할 수는 없다. POJO는 객체지향적인 자바 언어의 기본에 충실하게 만들어져야 하기 때문이다.

POJO의 장점

특정한 기술과 환경에 종속되지 않게 되므로 깔끔한 코드가 될 수 있다.
자동화된 테스트에 매우 유리하다(환경에 종속되지 않기 때문에)
객체지향적인 설계를 자유롭게 적용할 수 있다.

POJO 프레임워크
스프링을 이용하면 POJO 프로그래밍의 장점을 그대로 살려서 엔터프라이즈 애플리케이션의 핵심 로직을 객체지향적인 POJO를 기반으로 깔끔하게 구현하고, 동시에 엔터프라이즈 환경의 각종 서비스와 기술적인 필요를 POJO방식으로 만들어진 코드에 적용할 수 잇다.

기술영역에만 관여하고 비즈니스 로직을 담당하는 POJO에서는 모습을 감춘다. 데이터 액세스 로직이나 웹 UI 로직을 다룰 때만 최소한의 방법으로 관여한다. POJO 프레임워크로서 스프링은 자신을 직접 노출하지 않으면서 애플리케이션을 POJO로 쉽게 개발할 수 있게 지원해준다.

스프링의 기술

  • 제어의 역전/ 의존관계 주입
    유연한 확장을 가능하게 하기 위함.

DI 활용 방법

  • 핵심기능의 변경
  • 핵심기능의 동적인 변경
  • 부가기능의 추가
  • 인터페이스의 변경
  • 프록시
  • 템플릿과 콜백
  • 싱글톤과 오브젝트 스코프
  • 테스트

AOP
객체지향 기술은 복잡해져 가는 애플리케이션의 요구조건과 기술적인 난해함을 모두 해결하는데 한계가 있기도 하다.
AOP는 바로 이러한 객체지향 기술의 한계와 단점을 극복하도록 도와주는 보조적인 프로그래밍 기술이다.

  • 다이내믹 프록시를 활용하는 방법
    이 방법은 기존 코드에 영향을 주지 않고 부가기능을 적용하게 해주는 데코레이터 패턴을 응용한 것이다. 만들기 쉽고 적용하기 간편하지만 부가기능을 부여할 수 있는 곳은 메소드의 호출이 일어나는 지점뿐이라는 제약이 있다.
  • 자바 언어의 한계를 넘어서는 언어의 확장을 이용하는 방법
    메소드 호출뿐 아니라 인스턴스 생성, 필드 액세스, 특정 호출 경로를 가진 메소드 호출 등에도 부가기능을 제공할 수 있다. 이런 고급 AOP 기능을 적용하려면 자바 언어와 JDK의 지원만으로는 불가능하다. 그 대신 별도의 AOP 컴파일러를 이용한 빌드 과정을 거치거나, 클래스가 메모리로 로딩될 때 그 바이트 코드를 조작하는 위빙과 같은 별도의 방법을 이용해야 한다.

PSA

PSA는 환경과 세부 기술의 변화에 관계없이 일관된 방식으로 기술에 접근 할 수 있게 해준다.POJO로 개발된 코드는 특정 환경이나 구현 방식에 종속적이지 않아야 한다. 스프링은 JavaEE를 기존 플랫폼으로 하는 자바 엔터프라이즈 개발에 주로 사용된다. 따라서 다양한 JavaEE 기술에 의존적일 수밖에 없다 .특정 환경과 기술에 종속적이지 않다는 게 그런 기술을 사용하지 않는다는 뜻은 아니다. 다만 POJO 코드가 그런 기술에 직접 노출되어 만들어지지 않는다는 말이다. 이를 위해 스프링이 제공하는 대표적인 기술이 바로 일관성 있는 서비스 추상화 기술이다.

@jumining
Copy link

9장 스프링 프로젝트 시작하기

목표 : 애플리케이션 프로젝트를 처음 구성할 때 알아야할 기본적인 내용, 개발에 도움되는 개발 툴과 빌드 방법, 스프링을 애플리케이션에 적용할 수 있는 아키텍처의 종류와 특징 알아보기

자바 엔터프라이즈 플랫폼과 스프링 애플리케이션

스프링으로 만들 수 있는 애플리케이션의 종류에는 제한이 X 자바 언어를 사용하는 모든 종류의 프로젝트라면 어디든 사용 가능

스프링은 주로 자바 엔터프라이즈 환경에서 동작하는 애플리케이션을 개발하는 목적으로 사용됨

자바 엔터프라이즈 애플리케이션은 클라이언트의 요청을 받아 그에 대한 작업 수행 후 결과를 돌려주는 것이 기본 동작 방식이나 클라이언트 요청 없이도 정해진 시간이나 특정 이벤트 발생에 따라 독자적으로 작업 수행하기도함


- 클라이언트와 백엔드 시스템

'DB를 사용하는 웹 애플리케이션' 구조 : 클라이언트가 웹 브라우저이고 백엔드 시스템이 DB인 구성


클라이언트

: 웹 브라우저, RIA(Rich Internet Application), HTTP 이용해 통신하는 엔터프라이즈 시스템, .NET 애플리케이션


백엔드 시스템

: DB, 메시징 서버, 메일 서버, 메인 프레임, 웹 서비스를 제공하는 서버, 원격 EJB 서버

한 번에 여러 종류의 백엔드 시스템 이용 가능, 여러 개의 DB를 동시에 이용하는 것도 가능


- 애플리케이션 서버

스프링으로 만든 애플리케이션을 자바 서버 환경에 배포하려면 JavaEE(or J2EE) 서버가 필요


JavaEE 표준 따르는 애플리케이션 서버

  1. JavaEE 대부분의 표준 기술 지원하고 다양한 형태의 모듈로 배포가 가능한 완전한 웹 애플리케이션 서버(WAS)
  2. 웹 모듈의 배포만 가능한 경량급 WAS 또는 서블릿/JSP 컨테이너

1) 경량급 WAS/서블릿 컨테이너

톰캣, 제티 같은 가벼운 서블릿 컨테이너만 있어도 핵심기능 모두 이용하기에 충분

기존에 EJB나 WAS를 사용해야 가능했던 선언적인 트랜잭션이나 선언적 보안, DB 연결 풀링, 리모팅, 웹서비스 가능

추가적인 라이브러리 도움 받으면 분산/글로벌 트랜잭션까지 가능


2) WAS

고가의 WAS를 사용할 때의 장점 : 고도의 안정성, 안정적인 리소스 관리, 레거시 시스템의 연동 가능, 관리 기능이나 모니터링 기능이 뛰어나 여러 대의 서버를 동시에 운영할 때 유리

자바 엔터프라이즈 버전(JavaEE) 표준을 최대한 활용할 수 있음

대개는 서블릿 컨테이너로도 충분하기에 무겁고 다루기 힘들고 비싼 WAS를 사용할 때에는 분명한 이유를 가지고 사용하길 권장


스프링소스 tcServer

톰캣을 기반으로 엔터프라이즈 스프링 애플리케이션에 최적화된 경량급 애플리케이션 서버

기존 톰캣에서는 아쉬웠던 고급 서버 관리 기능, 배포 기능과 진단 기능을 포함해 톰캣 전문가에게 받는 기술지원 제공받기 가능

스프링 애플리케이션 개발과 운영에 꼭 필요한 중요한 기능이 많이 제공됨

👉언제 사용?
WAS 쓰기에 비싸서 부담이고 기술지원도 못받고 관리하기 불편한 톰캣을 그대로 사용하기 불안할 때 tcServer 사용


- 스프링애플리케이션의 배포 단위

스프링으로 만든 애플리케이션은 다음의 세 가지 단위로 배포


1) 독립 웹 모듈

가장 단순하고 편리한 배포 단위

보통 war로 패키징된 독립 웹 모듈로 배포

서블릿 컨테이너(톰캣) 사용 시 독립 웹 모듈이 유일한 방법이며 WAS 사용해도 대부분 이 방법


2) 엔터프라이즈 애플리케이션

확장자가 ear인 엔터프라이즈 애플리케이션으로 패키징해서 배포

하나 이상의 웹 모듈과 별도로 분리된 공유 가능한 스프링 컨텍스트를 엔터프라이즈 애플리케이션으로 묶어주는 방식


3) 백그라운드 서비스 모듈

J2EE 1.4에서 등장한 rar 패키징 방법

rar는 리소스 커넥터를 만들어 배포할 때 사용하는 방식으로 스프링으로 만든 애플리케이션이 UI 없이 서버 내에서 백그라운드 서비스처럼 동작할 필요가 있을 때 사용 (J2EE 1.4 이상의 표준을 따르는 WAS가 반드시 필요)

운영 플랫폼이나 서버의 종류는 개발 중에도 변경 가능 (설정만 바꾸면 이전이 가능)

특정 서버 환경에서만 제공하는 기능 사용하면 변경 어려움

👉 서버의 기능에 종속되지 않도록 주의하거나 쉽게 다른 서버 기능으로 변경 가능하도록 추상화해서 사용하기




개발도구와 환경

- JavaSE와 JavaEE

JavaSE/JDK

스프링 3.0은 JavaSE 5 버전에서 추가된 언어와 문법의 특징을 활용해서 개발됐기에 JDK 5.0 이상을 필요로 함


JavaEE/J2EE

스프링 3.0이 사용될 자바 엔터프라이즈 플랫폼으로는 J2EE 1.4이나 JavaEE 5.0이 필요


- IDE(통합 개발 환경)

자바 5 이상의 언어를 지원하는 자바 개발도구와 스키마를 지원하는 XML 편집기 정도만 있다면 어떤 개발환경에서든 개발 가능

IDE 사용하면 개발 툴을 떠나지 않고도 개발 과정에서 필요한 모든 일 처리 가능

ex) 이클립스, IntelliJ IDEA, 넷빈즈

  • 모두 무료로 사용 가능한 오픈소스 제품
  • 자바 엔터프라이즈 개발 지원 기능
  • 스프링 개발 지원 기능

![](https://velog.velcdn.com/images/jumining/post/619c86c6-f1cd-4d2e-a90f-2f73cc7f0f81/image.png)

- 라이브러리 관리와 빌드 툴

필요한 프레임워크 모듈과 라이브러리 파일을 선택해서 프로젝트의 빌드 패스에 넣어주는 일이 어려움

라이브러리 관리의 어려움

  1. 모든 모듈과 라이브러리가 매번 다 쓰이는 것이 아니고 필요한 기능과 사용하기로 결정한 기술에 따라서 적절하게 선택

  2. 라이브러리마다 여러 개의 버전이 존재하며 어떤 버전을 사용해야 할지 알아야함

라이브러리 의존관계 관리의 가장 큰 난제

같은 라이브러리의 두 가지 버전이 존재하는 애플리케이션의 의존관계가 있을 때, 이름이 같지만 구현이 다른 클래스가 있다면 이에 의존하고 있는 라이브러리 중 하나는 비정상적으로 동작함

재패키징으로 문제 해결 가능


재패키징

한쪽 버전의 클래스를 다른 패키지로 옮겨서 서로 구별되는 클래스로 만들어주는 방법

이에 의존하는 라이브러리의 코드도 변경된 패키지 내의 클래스를 사용하도록 수정 필요

모든 소스와 코드를 찾아서 수정해주는 작업이라서, 재패키징을 지원해주는 툴 존재 -> jarjar


빌드 툴이 지원하는 의존 라이브러리 관리 기능

자바의 대표적 빌드 툴 : Maven, ANT

IDE 사용 시 자동 빌드 가능

IDE 사용할 수 없는 환경(서버 배치했을 때나 통합 테스트 환경에서 애플리케이션 직접 빌드할 경우) 일관된 빌드가(IDE에서와 동일하게 애플리케이션 빌드 작업 수행) 가능하도록 만들어야함

👉 자동 빌드 기능 지원하는 IDE 이용하면서 ANTMaven과 같은 환경에 독립적인 빌드 툴 함께 사용하는 것이 바람직


Maven
: 빌드, 테스트, 배치, 문서화, 리포트 등 다양한 작업 지원
: POM이라고 하는 프로젝트 모델 정보를 이용함으로써 미리 정해진 절차에 따라 빌드 또는 프로젝트 관리 작업 지원 (선언적)
: POM 미리 만들어두면 의존 라이브러리와 동작하데 필요한 여타 라이브러리까지 자동 다운로드 가능 (전이적)

👉 장점 : 수십 메가에 달하는 라이브러리를 프로젝트 안에 포함시켜 소스코드와 관리하면 부담되는데, Maven 사용시 POM을 통해 의존 라이브러리 정보만 갖게 하고 필요한 라이브러리는 빌드 과정 중에 자동 다운 받거나 로컬 공통 리포지토리에서 가져오게 하면 프로젝트 파일 크기 줄어들고 코드 관리 단순해짐

전이적 의존관계 추적 기능에 의해 해당 그룹의 모든 라이브러리가 프로젝트에 자동으로 등록




애플리케이션 아키텍쳐

시스템 레벨의 아키텍처(클라이언트와 백엔드 시스템의 종류와 기술, 연동 방법) 결정 후에는 스프링 웹 애플리케이션의 아키텍처 결정 필요

응집도 높이고 결합도 낮추기 위해 인터페이스 사용


- 계층형 아키텍처

책임과 성격이 다른 것을 크게 그룹으로 만들어 분리해두는 것을 아키텍처 차원에서 계층형 아키텍처라고 부름

보통 웹 기반 엔터프라이즈 애플리케이션은 일반적으로 3개의 계층을 가져서 3계층 애플리케이션라고 부름


3계층 아키텍처와 수직 계층

1) 데이터 액세스 계층 (DAO 계층, EIS 계층)

: 백엔드의 DB나 레거시 시스템과 연동하는 인터페이스 역할

DAO 패턴 보편적으로 사용

ERP, 레거시 시스템, 메인프레임 등에 접근하기 때문에 EIS(Enterprise Information System)계층이라고 함

사용 기술에 따라 다시 세분화된 수직적인 계층으로 구분함

(추상화 레벨 높) DAO코드 - JdbcTemplate - JDBC/트랜잭션동기화 - DataSource (추상화 레벨 낮)


2) 서비스 계층

: 비즈니스 로직

이상적인 POJO로 작성

DAO 계층을 호출하고 이를 활용해서 만들어짐

서비스 계층 코드가 기반 서비스 계층(트랜잭션, 보안, 리모팅, 메일, 스케줄링 등)의 구현에 종속되면 안됨

서비스 계층의 코드는 추상화된 기반 서비스 인터페이스를 통해서만 접근하도록 만들기

서비스 계층은 백엔드 시스템과 연결되는 데이터 액세스 계층이 바뀌고 클라이언트와 연결되는 프레젠테이션 계층이 모두 바뀌어도 그대로 유지될 수 있어야 함

3) 프레젠테이션 계층

: UI 만들어내고 흐름 관리

매우 다양한 기술과 프레임워크의 조합이 가능

클라이언트의 종류와 상관없이 HTTP 프로토콜을 사용하는 서블릿이 바탕이 됨
(방화벽 문제/통합된 보안 문제로 인해 HTTP로 모두 수렴되는 추세)


계층형 아키텍처 설계의 원칙

각 계층은 응집도가 높으면서 다른 계층과는 낮은 결합도를 유지할 수 있어야 함

각 계층은 자신의 계층의 책임에만 충실해야 함

각 계층은 자신과 관련된 기술이 아닌 다른 기술 API 사용 삼가


- 애플리케이션 정보 아키텍처

사용자의 작업 상태를 오래 유지할 수 있는 독립 애플리케이션과 달리 엔터프라이즈 애플리케이션은 일반적응로 사용자의 요청을 처리하는 동안만 간단한 상태를 유지

애플리케이션의 주요 상태정보는 클라이언트나 백엔드 시스템에 분산돼서 보관됨 (장기 보관 정보는 DB나 메인프레임 같은 EIS 백엔드 시스템에 저장되고, 임시 정보는 클라이언트나 세션 메모리에 저장)

애플리케이션을 사이에 두고 정보를 어떤 식으로 다룰지 결정하는 일이 중요


데이터 중심 아키텍처

엔터프라이즈 애플리케이션에 존재하는 정보를 단순히 값이나 값을 담기 위한 목적의 오브젝트 형태로 다루는 경우

DB나 백엔드에서 가져온 정보를 값으로 다루고 그 값을 취급하는 코드 만들어 로직 구현하고 값을 그대로 프레젠테이션 계층의 뷰와 연결해주는 것

핵심 비즈니스 로직을 어디에 많이 두는지에 따라 DB에 무게를 두는 구조와 서비스 계층의 코드에 무게를 두는 구조로 구분 가능

하나의 업무 트랜잭션에 모든 계층의 코드가 종속되는 경향이 있음


거대한 서비스 계층 방식

DB에 많은 로직을 두는 개발 방법의 단점(안정성 떨어지고 코드 검증하기 힘들고 확장성 떨어짐)을 피하면서 애플리케이션 코드의 비중을 높이는 방법

DB에는 부하가 걸리지 않도록 저장 프로시저의 사용을 자제하고 복잡한 SQL을 피하면서, 주요 로직은 서비스 계층의 코드에서 처리하도록 만듬

많은 비즈니스 로직을 DB의 저장 프로시저나 SQL에서 서비스 계층의 오브젝트로 옮김으로써 애플리케이션 코드의 비중이 커짐 -> 구조 단순해지고 객체지향적임


- 오브젝트 중심 아키텍처

오브젝트를 만들어두고 오브젝트 구조 안에 정보를 담아서 각 계층 사이에 전달하게 만드는 것

데이터 중심 아키텍처와 다른 특징은 도메인 모델을 반영하는 오브젝트 구조를 만들어두고 그것을 각 계층 사이에서 정보를 전송하는데 사용한다는 것

객체지향 분석과 모델링의 결과로 나오는 도메인 모델을 오브젝트 모델로 활용

오브젝트 구조로 정보 갖고 있으면 어떤 식으로든 활용하기 편리


데이터와 오브젝트 방식 비교

데이터 중심의 아키텍처에서는 DAO가 만드는 SQL 결과에 모든 계층의 코드가 의존하게 됨

오브젝트 방식에서는 애플리케이션에서 사용되는 정보가 도메인 모델의 구조를 반영해서 만들어진 오브젝트 안에 담기고 도메인 모델은 애플리케이션 전 계층에서 동일한 의미를 가짐
따라서 도메인 모델이 반영된 도메인 오브젝트도 전 계층에서 일관된 구조를 유지한 채로 사용됨


도메인 오브젝트 사용의 문제점

최적화된 SQL을 매번 만들어 사용하는 경우에 비해 성능 면에서 조금은 손해

DAO는 비즈니스 로직의 사용 방식을 알지 못하므로, 도메인 오브젝트의 모든 필드 값을 다 채워서 전달하는 경우가 대부분인데 하나의 오브젝트에 담긴 필드의 개수가 많아지다 보면 그중에는 드물게 사용되는 필드도 있을 수 있음 -> 낭비

하나의 정보만 필요한 비즈니스 로직에서 오브젝트 하나를 다 가져오는 경우 필요없는 정보도 다 가져오기 때문에 낭비


최적화 방법

지연된 로딩 기법 : 일단 최소한의 오브젝트 정보만 읽어두고 관계하고 있는 오브젝트가 필요한 경우에만 다이내믹하게 DB에서 다시 읽어옴

데이터 액세스 기술 활용 : JPA, JDO, 하이버네이트, TopLinK와 같은 오브젝트/RDB 매핑 기술(ORM)은 기본적으로 지연된 로딩 기법 제공해주고, 많이 사용하는 테이블은 ORM이 제공해주는 오브젝트 캐시에 넣어 활용 가능

👉 ORM 사용 권장


빈약한 도메인 오브젝트 방식

오브젝트 중심 아키텍처는 오브젝트의 활용 방법을 기준으로 구분 가능

빈약한 오브젝트 : 도메인 오브젝트에 정보만 담겨있고 활용하는 아무런 기능도 갖고 있지 않을 때

비즈니스 로직은 서비스 계층에 담김 -> 거대 서비스 계층 구조와 유사


풍성(영리)한 도메인 오브젝트 방식

특정 도메인 오브젝트나 관련 오브젝트가 가진 정보와 깊은 관계가 있는 비즈니스 로직을 서비스 계층의 코드가 아니라 도메인 오브젝트에 넣어주고, 서비스 계층의 비즈니스 로직에서 재사용하게 만듬

도메인 오브젝트의 객체지향적인 특징을 잘 활용하였고 코드 간결

*도메인 오브젝트는 스프링 컨테이너가 관리하는 즉 빈이 아니기 때문에 DAO 오브젝트를 DI 받을 수 없음

도메인 계층의 역할과 비중을 극대화하려다 보면 기존의 풍성한 도메인 오브젝트 방식으로는 부족


도메인 계층 방식

도메인 오브젝트가 기존 3계층과 같은 레벨로 격상되어 하나의 계층을 이루게 하는 방식

도메인 오브젝트들이 하나의 독립적인 계층을 이뤄서 서비스 계층과 데이터 액세스 계층의 사이에 존재하게 하는 것이 개념


달라지는 특징 두가지

  1. 도메인에 종속적인 비즈니스 로직의 처리는 서비스 계층이 아니라 도메인 계층의 오브젝트 안에서 진행됨도메인 계층으로 들어가면 서비스 계층의 도움 없이도 비즈니스 로직의 대부분의 작업을 수행 가능

  2. 도메인 오브젝트가 기존 데이터 액세스 계층이나 기반 계층의 기능을 직접 활용 가능
    스프링이 관리하지 않는 도메인 오브젝트에 DI 적용 위해 AOP 사용(AOP 부가기능으로 DI서비스를 도메인 오브젝트에 적용)




- 스프링 애플리케이션을 위한 아키텍처 설계

3단계로 분리하는 계층형 아키텍처와 정보를 다루는 방법에 따른 아키텍처 정보를 위에서 알아봄.

계층구조를 어떻게 나눌 것인가와 애플리케이션 정보를 어떻게 다룰지를 결정하는 것이 기본, 그 위에 각 계층에 사용될 구체적인 기술의 종류와 수직 추상화 계층의 도입, 세세한 기술적인 조건을 결정하는 일 필요


상태 관리와 빈 스코프

아키텍처 설계에서 신경 써야 할 사항은 상태 관리

서버의 자원이 특정 사용자에게 일정하게 할당되지 않아 지속적으로 유지되는 상태를 갖지 X

스프링은 기본적으로 상태가 유지되지 않는 빈과 오브젝트를 사용하는 것을 권장
(웹의 생리에 잘 들어맞고 개발 쉽고 서버 확장이 쉬워서)

상태는 클라이언트, 백엔드에 저장하거나 세션 정도에 일시적으로 저장하는 것이 대부분

장기간 유지되며 중첩될 수 있는 상태 정보는 고급 상태 관리 기법 이용


'스프링이 지원하는 기술'의 의미

스프링은 거의 대부분의 자바 표준 기술과 함께 사용 가능

  1. 해당 기술을 스프링의 DI 패턴을 따라 사용 가능

    • 프레임워크나 라이브러리의 핵심 클래스를 빈으로 등록할 수 있게 지원해주는 것
  2. 스프링의 서비스 추상화가 적용됨

    • 비슷한 기능을 제공하는 기술에 대한 일관된 접근 방법을 정의해주고 이를 통해 서드파티 프레임워크를 적용할 수 있을 뿐 아니라 필요에 따라 호환 가능한 기술로 손쉽게 교체해서 사용 가능
    • 서비스 추상화 인터페이스를 구현한 클래스들은 모두 스프링의 빈으로 등록되도록 만들어짐
  3. 스프링이 지지하는 프로그래밍 모델을 적용

    • 대표 예시) 스프링의 데이터 액세스 기술에 대한 일관된 예외 적용 : 데이터 액세스 기술 종류 상관 없이 일관된 예외 계층구조 따라 예외 던져짐
    • 서비스 계층의 비즈니스 로직을 담은 코드가 데이터 액세스 계층의 기술에 종속되지 않도록 만들어줌
  4. 템플릿/콜백이 지원

    • 스프링은 JDBC, JMS, JCA를 비롯한 여러 기술을 지원하고 간편하게 사용할 수 있도록 템플릿/콜백 기능을 제공

👉 스프링이 지지하는 개발철학과 프로그래밍 모델을 따라 해당 기술을 사용할 수 있다는 의미

@leesewon00
Copy link
Member

📚7.5 ~ 7.7장 정리

7.5 DI를 이용해 다양한 구현 방법 적용하기

  • SqlRegistry는 동시성 문제가 발생할 일이 없다. 초기화하면서 쓰기 작업을 마친 후, 변경될 일이 없이 읽기 전용처럼 작동하기 때문이다.
  • 하지만 SQL을 수정할 수 있도록 만드려면 어느 정도 쓰레드 안전을 보장할 수 있어야 한다.

ConcurrentHashMap 사용하기

  • 지금까지 사용했던 JDK의 HashMap은 멀티스레드 환경에서
    여러 사용자가 동시에 수정을 요청할 경우 동시성 문제를 일으킬 수 있다.
  • 따라서 동기화된 해시 데이터 조작에 최적화되도록 만들어진 ConcurrentHashMap을 사용하는 방법이 권장된다.
  • ConcurrentHashMap은 수정 시에 전체 데이터에 lock을 걸지도 않으며,
    조회 시에는 lock 자체가 없어서 성능 면에서 효율적이다.
private Map<String, String> sqlMap = new HashMap<String, String>();

내장형 데이터베이스 이용한 sql 레지스트리 만들기

  • 그러나 ConcurrentHashMap은 변경이 자주 일어나는 환경에선 동기화의 성능하락에서 자유로울 수 없다. 그래서 SQL을 담는 DB같은 것을 설계해볼 순 있지만, 관계형 데이터베이스 스키마를 구현하는 것은 배보다 배꼽이 더 커질 수가 있다.
  • 그래서 내장형 DB를 고려해볼 수 있다.
  • 내장형 DB는 애플리케이션에 내장돼서 애플리케이션과 함께 시작되고 종료되는 DB를 말한다.

스프링의 내장형 DB 지원

  • 내장형 DB는 애플리케이션과 생명 주기가 동일하기 때문에
    애플리케이션 내에서 DB를 초기화하는 작업이 필요하다.
  • 대신 스프링이 내장형 DB 빌더를 제공하고 있다.
    따라서 JDBC 접속 URL을 통해 연결을 시도하면 JDBC 드라이버 내에서
    DB 인스턴스를 생성하는 방식이다.
  • 다만 내장형 DB는 애플리케이션 내에서 초기화하는 것과 동일하게 종료할 수도 있어야 하므로
    스프링에서는 DataSource 인터페이스를 상속하는 EmbeddedDatabase 인터페이스를 제공한다.
new EmbeddedDatabaseBuilder()
        .setType(내장형DB종류)
        .addScript(초기화에 사용할 DB 스크립트의 리소스)
        ...
        .build()
  • 이와 같은 로직을 통해 마지막의 build()가 EmbeddedDatabase 오브젝트를 돌려준다.
  • 그리고 EmbeddedDatabase는 DataSource를 상속했기 때문에
    JdbcTemplate을 활용해 접근할 수 있다.
  • 따라서 이전에 DAO에서 썼던 로직 그대로 이용할 수 있다.

내장형 DB를 이용한 SqlRegistry 만들기

  • jdbc 스키마에 내장형 DB 빈을 생성하는 팩토리 빈 태그들이 정의되어 있다.
  • 이로 인해 EmbeddedDatabase 타입이고 이름이 embeddedDatabase인 빈이 생성된다.
  • 이제 DataSource를 DI 받는 UpdatableSqlRegistry를 구현하면 된다.
public class EmbeddedDbSqlRegistry implements UpdatableSqlRegistry {
    private JdbcTemplate jdbcTemplate;
    public void setDataSource(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
    }    
    ...

트랜잭션 적용

  • 전에 AOP 썼을 때와 달리
    EmbeddedDbSqlRegistry 한 클래스 안에서만 처리해주면 되기 때문에
    그냥 트랜잭션 추상화 API를 직접 사용한다.
  • EmbeddedDbSqlRegistry 클래스에 트랜잭션을 추가하여 리팩토링 해야한다.
    다만, 이전에 추상화 서비스에서 배운 PlatformTransactionManager가 아니라,
    DataSourceTransactionManager를 사용한다.
  • EmebeddedDbSqlRegistry는 내장형 DB만을 사용한다는 보장이 있기 때문에
    다른 트랜잭션 기술들을 포괄할 필요가 없기 때문이다.
public class EmbeddedDbSqlRegistry implements UpdatableSqlRegistry {
    private JdbcTemplate jdbcTemplate;
    private TransactionTemplate transactionTemplate;
    public void setDataSource(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
        transactionTemplate = new TransactionTemplate(new DataSourceTransactionManager(dataSource));
    }
    ...
  • 추가적으로 DataSource의 setter 내에서 트랜잭션 템플릿도 트랜잭션 매니저를 생성하면서 DataSource를 받아준다.
    그리고 트랜잭션을 적용해야 하는 updateSql()에서는 execute()를 하고
    템플릿 / 콜백 패턴을 활용하여 sqlmap의 쿼리들을 수정하는 작업을 트랜잭션 내에서 진행하도록 해준다.
public class EmbeddedDbSqlRegistry implements UpdateSqlRegistry {
    SimpleJdbcTemplate jdbc;
    TransactionTemplate transactionTemplate;

    public void setDataSource(DataSource dataSource) {
        jdbc = new SimpleJdbcTemplate(dataSource);
        transactionTemplate = new TransactionTemplate(
                new DataSourceTransactionManager(dataSource));
        // DataSource의 setter 내에서 트랜잭션 템플릿도 트랜잭션 매니저를 생성하면서 DataSource를 받아준다.
    }
    
    public void updateSql(final Map<String, String> sqlmap) throws SqlUpdateFailureException {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                //트랜잭션을 적용해야 하는 updateSql()에서는 execute()를 하고
                //템플릿 / 콜백 패턴을 활용하여 sqlmap의 쿼리들을 수정하는 작업을 트랜잭션 내에서 진행하도록 해준다.
              for (Map.Entry<String, String> entry : sqlmap.entrySet()) {
                    updateSql(entry.getKey(), entry.getValue());
                }
            }
        });
    }
}

다음과같이 SQL을 서버에서 런타임에 수정한다는 가정 하에 발생할 수 있는 동시성 문제를 방지할 수 있는 SqlRegistry를 구현할 수 있다.

7.6. 스프링 3.1의 DI

  • 스프링이 제공하는 모든 기술의 기초가 되는 DI의 원리는 변하지 않았지만,
    코드를 작성할 때 사용하는 핵심 도구인 자바 언어에는 적지 않은 변화가 있었다.
  • 이런 변화들이 DI 프레임워크로서 스프링 사용 방식에도 여러 영향을 주었다.
  • 대표적인 두 가지 변화를 살펴보자.

애노테이션의 메타정보 활용

  • 애노테이션 특징을 살펴보자

  • 애노테이션은 코드 실행에 직접적으로 영향을 끼치지 못하고, 인터페이스처럼 타입을 부여하는 것도 아니며, 오버라이드나 상속이 불가능하다.

  • 대신 프레임워크가 코드의 특성을 분석할 수 있는 메타정보로써 활용된다.

  • 애노테이션이 부여된 클래스나 메서드의 패키지, 클래스 이름, 메서드 시그니쳐, 접근제한자, 상속한 클래스나 구현 인터페이스 등을 알 수 있다.

  • 애노테이션 활용이 늘어난 이유?

  • 핵심로직을 담은 자바코드, 이를 활용한 IoC 프레임워크, 프레임워크가 참조하는 메타정보 세가지로 구성하는 방식에 잘어울리기 때문이다.

  • 애노테이션 장점 : 작성해야 하는 코드량이 적고 직관적이며 해당 타깃의 다양한 부가 메타정보를 얻을 수 있다.

정책과 관례를 이용한 프로그래밍

  • 애노테이션 같은 메타정보를 활용하는 이유는 코드로 동작 내용을 구체적으로 구현하는 대신, 미리 약속한 규칙이나 관례를 따라 구현했다면, 애너테이션으로 쉽게 부가적인 것들을 부여할 수 있다.
  • 반복되는 부분을 줄여주고 빠르게 구현할 수 있다는 장점이 있다.
  • 반면에 이 모든 규칙들을 익히는 러닝 커브와 방대한 분량이 문제가 된다. ex) Transactional

7.6.1~

xml을 애노테이션과 자바코드로 대체하기

@configuration

  • DI 정보로 사용될 자바 클래스를 만들 때 @configuration 애노테이션을 사용한다. 해당 애너테이션이 붙은 클래스는 앞으로 XML을 대신하여 DI 설정정보로 이용될 것이다.
@Configuration
public class TestApplicationContext {
    ...
}

@bean

  • @configuration이 붙은 클래스에 Bean 정보를 만들어주면 된다.
  • bean 태그에 정의된 DI 정보는 @bean이 붙은 메서드와 1:1로 매핑된다.
  • @bean@configuration이 붙은 DI 설정용 클래스에서 사용된다.
...
@Bean
public MailSender mailSender() {
        return new DummyMailSender();
        }

@Autowired

  • XML의 프로퍼티를 이용해 자바 코드로 작성한 DI 정보를 참조할 수 있었지만, XML에 작성된 DI 정보를 자바 코드에선 어떻게 참조할까? @Autowired를 이용할 수 있다.
  • @Autowired는 필드의 타입과 빈의 타입이 일치하면 빈을 자동으로 주입해준다. 빈의 프로퍼티 설정을 직접 해주는 자바 코드나 XML의 양을 줄일 수 있다.
  • 찾는 순서 : 타입 -> 이름 -> @qualifier -> 실패
  • 사용 위치 : 멤버변수, setter 메소드, 생성자, 일반 메소드
@Autowired
public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
}

@component

  • 이 애노테이션이 붙어있는 클래스는 빈스캐너를 통해 자동으로 빈으로 등록된다.
  • 정확하게는 @component 애노테이션 혹은 @component를 메타 애노테이션으로 갖고 있는 애노테이션이 붙은 클래스가 자동 빈 등록 대상이 된다.
@Component
public class UserDaoJdbc implements UserDao {
    ...
}

메타 애노테이션

  • 애노테이션의 정의에 부여된 애노테이션을 의미한다.
  • 빈 스캔을 통해 자동등록 대상으로 인식하게 하려면 @component를 붙여주면 된다.
@Component
public @interface SnsConnector{
    ...
}

@componentscan

  • @component가 부착된 클래스를 찾으면 자동으로 Bean으로 등록하며,
  • 특별히 Bean의 아이디를 지정하지 않았다면(@component("{Bean의 아이디}")와 같이 지정할 수 있다)
    클래스의 첫 글자를 소문자로 바꾸어 아이디로 사용한다.
  • 기준 패키지의 서브 패키지를 모두 검색해서 적용한다.
  • 여러 패키지를 등록할 수 있다.
@ComponentScan(basePackages="springbook.user")
public class TestApplicationContext {
    ...
}

@import (컨텍스트 분리)

  • 분리한 설정파일을 다른곳에서 가져다 쓰고싶을 때 사용하는 것이 import다.
@Import(SqlServiceContext.class)
public class AppContext { ... }

@Profile, @ActiceProfiles

  • 스프링 3.1은 환경에 따라 설정정보가 달라져야할 경우에 파일을 여러개로 분리하는 형태가 아닌 간단한 설정정보를 구성할 수 있도록 Profile 애노테이션을 지원한다.
@Profile("test")
public class TestAppContext { ... }
  • 이렇게만 해주면, test 라는 프로파일의 설정정보를 담은 클래스가 된 것이다.
  • 이제 상황에 따라 ActiveProfile을 지정하면, 특정 테스트시 프로파일에 맞는 Context 정보를 가져올 수 있다.
@ActiveProfile("test")
public class UserServiceTest { ... }
  • 이제 별도의 조합 없이 원하는 환경에 따라 Context 정보를 주입할 수 있게 되었다.

@enable*

  • 일반적으로 Import 애노테이션 보다는, 관용적으로 접두사 Enable로 시작하는 애노테이션을 이용하여 특정 기능을 사용하겠다는 것을 명시적으로 보여줄 수 있다.
  • 예를 들면 아래와 같이 제작할 수 있다.
@Import(value=SqlServiceContext.class)
public @interface EnableSqlService { ... }
  • @EnableSqlService가 결국 SqlServiceContext.class를 import하겠다는 의미를 지니는 것이다.
  • 스프링 3.1에서는 이와 같은 형태로 지정된 다양한 클래스들이 있는데, 대표적으로 TransactionManagement가 있다.
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement { ... }
  • 이를 적용하면 Import를 사용하지 않고도 특정 모듈을 사용하겠다는 의미를 잘 드러낼 수 있다.
@EnableSqlService
public class AppContext implements SqlMapConfig { ... }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants