스프링 입문 1. 스프링과 웹 애플리케이션

10 Jan 2019 - breadkey

스프링의 최신 정보

스프링의 역사

2002년 등장
2006년 SSH(스트럿츠, 스프링, 하이버네이트)구성으로 웹 애플리케이션 프레임워크로 이용

현재는 스트럿츠 < 스프링MVC

스프링 서브 프로젝트

  • 초기
    스프링 웹 플로: 화면 전환의 흐름을 관리
  • 추가
    스프링 시큐리티: 인증/허가 처리를 관리
    스프링 배치: 일괄 처리용
  • 최근
    스프링 부트: 애플리케이션 개발을 간단하게 해줌

웹 애플리케이션 기반에서 엔터프라이즈 시스템의 기반으로, 비즈니스 아이디어를 시스템으로 빠르게 만들어줄 수 있는 기반으로 발전하였다.
작은 시스템부터 큰 시스템까지 모두 대응 가능하다.

스프링의 국내 동향

전자 정부 표준 프레임워크와 기반 기술

한국 스프링 사용자 모임

비영리적 컨퍼런스 스프링 캠프

스프링 교육 관련 정보

공식 교육 과정
자격 시험 존재하지만 영어로만 제공


스프링과 웹 애플리케이션

스프링은 웹앱에 특화된 프레임워크가 아니라 규모가 큰 애플리케이션을 자바로 만들 때 필요한 프레임워크이다.
구현을 위한 프레임워크가 아닌 설계를 위한 프레임워크이다.

웹 애플리케이션이란?

WWW가 유행하게 된 이유

컴퓨터와 인연이 없는 사람도 컴퓨터를 켜고 웹 브라우저만 사용할 수 있으면 간단히 이용할 수 있는 기술이기 때문이다.

웹 시스템의 기본적인 구조

정적 콘텐츠: 클라이언트의 웹 브라우저가 웹 서버로부터 요청한 HTML을 읽어와서 표시한다.
 
동적 콘텐츠: 웹 서버에서 애플리케이션 서버에 처리를 요청하고 처리 결과(대부분 RDB에서 데이터를 읽어오거나 가공)를 웹 서버에서 받아 웹 브라우저에 표시한다.
 
현재: Ajax등으로 웹 브라우저에 풍부한 화면을 구현할 수 있다. RDB 대신 KVS를 사용하는 경우도 많고, 클라이언트가 스마트폰인 경우도 많다. 서비스의 실체가 클라우드 안에 숨어있어 단순히 메일같은 인터넷상의 서비스로 존재할 때도 있지만 기본적인 동작은 위와 다를게 없다.
 
구체적으로 다음과 같은 동작의 반복이다.

  1. 웹 브라우저에서 버튼을 클릭
  2. 버튼에 대응한 비즈니스 로직이 RDB의 데이터를 이용해서 처리 진행
  3. 처리 결과를 전송
  4. 웹 브라우저에 표시

주의해야할 점은 “3. 처리 결과를 전송”” 후 세션이 끊어져버리는 것이다. 이렇게 되면 상태를 저장할 수 없다.(물론 이는 HTTP 1.1+ 등 현재의 기술로 당연히 해결 가능하다.)

자바 엔터프라이즈의 역사

  • HTML
    • 정적 콘텐츠
  • CGI
    • 동적 콘텐츠이나 1요청 1프로세스로 세션 관리가 없다.
  • 서블릿, JSP
    • CGI의 문제점을 해결했으며 자바를 사용한다.
  • EJB(3.0 이전)
    • 컴포넌트 모델의 업계 표준이며 분산 오브젝트를 지원한다.
  • 스프링
    • J2EE의 단점을 개선하려는 목적으로 만들어 졌으며 현재 클라우드 시대를 주도하고있다.

스프링을 왜 쓰는지 이해하려면 과거 기술들의 문제점을 알아야 한다.

JSP, Servlet의 등장

단순히 정적 콘텐츠만 표시하는 것은 업무에 이용하기에 기능이 부족했다.
 
CGI 기술 등장: HTTP의 요청으로 인해 실행되는 프로그램이다. 이로인해 같은 요청의 처리 결과로 다른 콘텐츠, 즉 동적 콘텐츠를 반환할 수 있게 되었다. 처리를 요청할 때마다 프로그램이 실행된다는 점과(생명주기 X) 세션 관리가 없다는 점이 문제가 되었다. 이는 이용자가 많아지면 많아질수록 커다란 성능 문제를 일으키고 트랜잭션 관리의 어려움을 초래했다.
 
JSP, Servlet 등장: 위의 문제점을 해결하고자 등장했다. 멀티 스레드로 실행되며, 컨테이너를 통한 세션 관리를 알아서 해주어 개발자가 이를 신경쓰지 않아도 되게 해주었다. 또한 페이지 생성 로직과 비즈니스 로직을 분리하기 곤란했던 CGI와 달리 JSP로 페이지를 생성하고 Servlet으로 비즈니스 로직을 처리할 수 있게 해주는 장점을 가져 널리 보급되었다.

EJB의 등장과 쇠퇴

EJB 컨테이너에 의해 분산된 EJB 컴포넌트를 마치 같은 머신에 있는 것처럼 접근할 수 있게 하거나, 분산된 데이터베이스의 트랜잭션을 마치 하나의 데이터베이스만 있는 것처럼 제어할 수 있는 분산 처리와 분산 트랜잭션의 융합 컴포넌트로 탄생한 기술이다.
 
이렇게 탄생했지만 웹 애플리케이션용 재사용할 수 있는 컴포넌트SQL 기술이 필요 없는 DB 액세스 프레임워크라는 오해를 받아 그렇게 되버렸다. 이에 따라 JSP, Servlet으로 프레젠테이션을 구현하고 EJB로 비즈니스 로직을 구현하는 것이 웹 앱의 권장 설계가 되었다.
 
그런데 실제 웹 애플리케이션은 분산 처리를 거의 사용하지 않으며 로컬 액세스가 필요하기 때문에 EJB는 부적합 했고, EJB 컨테이너에 의존하는 EJB는 테스트하기도 어려웠고, 사양도 복잡해 많은 개발자들이 멀리하게 되었다.
 
이는 스프링의 탄생 배경이 되었고 현재 EJB 3이후(이전과는 아예 다른 제품이다) 오히려 EJB는 스프링을 따라갔다.

스프링의 등장

복잡하고 무거워진 J2EE의 컨테이너를 대신할 경랑 컨테이너 스프링이 등장했다.(지금은 스프링도 많이 무거워졌다.) 스프링은 DIxAOP 컨테이너인데, EJB의 장점인 트랜잭션 관리를 POJO라고 부르는 일반 자바 오브젝트로 구현할 수 있다. 또한 기존 EJB 컨테이너에 실어야 했던 EJB 컴포넌트는 EJB에 대한 의존으로 인해 테스트하기 어려웠는데, DIxAOP 컨테이너에는 POJO 오브젝트를 싣고 DI 컨테이너에 의존하지 않는다는 특징 덕분에 테스트도 쉽게 할 수 있다.

스프링의 현재

사실상 표준이다. 우리나라에서도 전자 정부 표준 프레임워크이다. 자바가 클라우드를 향해 진화하므로 클라우드를 지향하는 스프링은 더욱 더 중요해질 것이다.


애플리케이션 아키텍처

애플리케이션 아키텍처의 필요성

웹 애플리케이션 개발의 목표

  1. 유스 케이스 등으로 표현되는 사용자 요구사항을 만족하다는 목표
  2. 개발 기간 엄수나 변경, 기능 추가의 용이성, 테스트의 용이성 등 개발자나 운영자를 위한 목표
    개발 효율
    • 의도를 파악하기 쉽고 이해하기 쉬운 구조
    • 테스트하기 쉬운 구조

유연성 * 변경하기 쉽고 기능을 추가하기 쉬운 구조 * 미래의 환경 변화에 대응할 수 있는 견고한 구조

물론 2번째의 목표를 만족하기 위해서는 사용자 요구사항을 만족하는 것이 전제 조건이다.

개발 효율성과 애플리케이션 아키텍처의 필요성

이해하기 쉽고 간단히 사용할 수 있어야 한다. 테스트도 마찬가지로 어떤 오브젝트를 테스트하기 위해 컨테이너를 꼭 준비해야 하거나 이것저것 설정해야 하거나 테스트를 위해 구현을 변경하는 것은 귀찮은 작업이다. 테스트는 간단하게 실행할 수 있는 것이 좋다.

웹 애플리케이션의 생명주기와 애플리케이션 아키텍처의 필요성

사용자의 요구가 쉽게 변하기 때문에 요구 변화 -> 변경 및 기능 추가 -> 릴리스 이 생명주기가 계속 반복된다. 따라서 아키텍처가 유연하지 못하다면 요구 변화에 대응하지 못해 애플리케이션을 유지하기 어려워진다.

애플리케이션 아키텍처는 자유로운 발상으로

사용자의 요구나 여러 조건에 따라 JSP(MVC로 치면 View로 볼 수 있음)로 데이터베이스에 직접 접근하는 것도 좋은 방법이다. 정석이라는 이유로 안 된다고 하는 것은 창조력을 방해한다.
 
사용자의 요구, 개발자/운영자의 요구 두 가지 목표를 만족하는 애플리케이션 아키텍처가 프레임워크나 라이브러리로 구현돼 매뉴얼과 함께 초기 개발 단계에서 개발자에게 제공되는 개발을 지향하여야 한다.

티어와 레이어

티어는 클라이언트(PC나 스마트폰 등), 중간(애플리케이션 서버), EIS(DB, 레거시 시스템) 3 층을 기본으로 하는 물리층이다.
 
레이어는 기본적으로 중간층에 있는 웹 애플리케이션을 논리적으로 분류한 것이다. 그러나 무조건적으로 레이어가 중간층에만 존재하는 것이 아니고 스마트폰 등인 경우 레이어의 일부가 클라이언트에 존재한다. 레이어는 서로 인접한 레이어끼리만 단방향 액세스를 할 수 있다. 일반적으로 다음처럼 3층으로 나뉜다.

  • 프레젠테이션 층: UI와 컨트롤러를 제공한다. Controller나 Action이 붙은 클래스가 배치된다.
  • 비즈니스 로직 층: Service가 붙은 유스 케이스를 제어하는 클래스나 액터 클래스가 배치된다.
  • 데이터 액세스 층: 데이터베이스 액세스를 추상화한다. 클래스 이름 끝에 DAO(Data Access Object)가 붙는다.
 
용어들은 다른 이름이 붙기도 하지만 용어가 통일되지 않으면 개발자 사이의 의사소통을 방해하므로 용어를 통일해야 한다.
 
컨트롤러
화면 전환이나 화면에서 버튼을 눌렀을 때의 동작 제어 또는 세션 관리 등을 함
비즈니스 로직
서비스(애플리케이션)
유스 케이스로 표현되는 특정 업무나 특정 부서 처리의 통합, 트랜잭션의 기점, 일반적으로 자신의 상태를 나타내는 값을 가지지 않는 클래스
도메인
서비스로부터 비즈니스를 실행하는 데 반드시 사용하는 고객과 주문같은 클래의 집함. 자신이 무엇인지 나타내는 값과 그 값을 이용한 처리를 실현

레이어끼리 단방향 액세스가 아닌 상호 의존을 하고 있는 관계라면 리팩토링 하는것이 좋다.

오목형 레이어

웹 애플리케이션의 레이어는 크게 비즈니스와 관련된 부분비즈니스 로직의 결과를 어떻게 표현할지 구현하는 두 부분으로 나뉠 수 있다. 비즈니스 로직의 결과를 어떻게 다룰지 구현하는 기술이 비즈니스 로직에 영향을 미치지 않는 것이 좋은 설계이다. 결과를 표현하는 방법은 화면에 표시, DB에 저장으로 나뉘는데 기존 세로형 레이어의 형태로는 불가능하다. 따라서 등장한 것이 오목형 레이어이다.

오목형 레이어 UML

안정 의존 원칙의존 관계 역전 원칙 등에 뒷받침된 건실한 구조이다.
비즈니스 로직 층이 가장 안정돼야 하므로 가장 밑에 있는 안정 의존 원칙과 다른 패키지에 가장 큰 영향을 줄 것 같은 위치에 데이터 액세스 층이 있으므로 비즈니스 로직 층과 의존 관게를 역전한 구조이다.


프레젠테이션 층의 역할

주된 역할은 사용자 인터페이스와 컨트롤러를 제공하는 것이다.
 
UI는 보통 화면을 가르키는 것으로 한다.
 
컨트롤러는 UI의 입력을 받아 비즈니스 로직을 호출하고, 그 결과를 UI에 반환하는 작업을 한다.

MVC2란?

예전 J2EE의 MVC2는 MVC 패턴을 참고한 것으로, Model 부분에 EJB, View 부분에 JSP, Controller 부분에 Servlet을 사용한다.

J2EE의 MVC2

스프링에서 일반적으로 컨트롤러는 스프링 MVC를 사용한다. 프로젝트 때마다 처음부터 컨트롤러를 직접 만드는 것은 낭비이다.

다양화되는 사용자 인터페이스

현재 UI를 구현하는 방법은 리액트, 앵귤러를 이용하는 등 매우 다양하다. 프레젠테이션 층은 사용자의 요청에 따라 패턴이 늘어 매우 다양하게 발전했다. 이에 따라 아키텍처 면에서 구문 검증은 웹 애플리케이션 중간 층에서 실행되지만, Ajax를 사용한 경우 클라이언트 층에서 실행될 때도 있다. 스마트폰 등에서는 그 자체를 클라이언트 층으로 보고 별도의 애플리케이션 레이어를 배치하기도 한다.


비즈니스 로직 층의 역할

웹 애플리케이션의 중심이다.
 
기능 추가와 변경은 주로 비즈니스 로직 층의 로직 변경이다. 프레젠테이션 층과 데이터 액세스 층에서는 신뢰성 있는 프레임워크를 이용하면 장애 등의 리스크를 거의 피할 수 있으나 비즈니스 로직에는 업무용 프레임워크가 적다. 더군다나 비즈니스 로직 층에서 구현하고 싶은 업무를 가장 잘 아는 것은 개발자가 아닌 사용자이다. 실패한 프로젝트의 대부분은 사용자와의 커뮤니케이션 문제, 비즈니스 로직 층의 구조 문제였다.

비즈니스 로직 층의 패턴

트랜잭션 스크립트

데이터베이스의 내용을 표시/변경하기만 하는 업무 처리, 즉 비즈니스 로직이 적은 단순 입출력 애플리케이션일 때는 로직을 전부 서비스 클래스에 포함시키는 편이 좋다. 이로인해 도메인은 그저 값을 저장하기만 하므로 VO(Value Object)나 DTO(Data Transfer Objet)라고 부르는 것이 된다.

도에인 모델

비즈니스 로직이 복잡해짐에 따라 트랜잭션 스크립트만으로 개발하면 굉장히 복잡해질 수 있다. 이에따라 도메인에 로직을 포함시키는 것이 좋지만 한계를 느끼면 트랜잭션 스크립트로 전환하는 것이 좋다.
 
스프링은 도메인 모델에 도움이 되지 않는다. 도메인 모델은 도메인에게 값을 처리할 것을 요구하는데, 스프링에서 도메인의 생성과 관리는 DIxAOP 컨테이너가 아닌 데이터 액세스 층의 구조에 의존하기 때문이다.

트랜잭션 관리

간단히 말하면 처리 단위이다. 웹 사이트에서 검색해서 상품 목록을 보는 과정도 트랜잭션이고, 웹 사이트에서 상품을 주문해서 집에 도착하기까지도 하나의 긴 트랜잭션이다. 다양한 트랜잭션이 있지만 여기서는 데이터베이스 트랜잭션만 다룬다.
 
트랜잭션에서는 ACID라는 지켜야 할 특성이 존재한다. 이 중 신경써야 하는 것은 A와 I이다.

ACID 의미 설명
Atomicity 트랜잭션의 원자성 트랜잭션 내의 모든 처리는 전부 실행됐거나 아무것도 실행되지 않았다.
Consistency 데이터의 일관성 데이터에 일관성이 있어야 한다. -일관성을 지키지 않은 예: 상위 테이블이 없는데 하위 테이블이 있는 경우
Isolation 트랜잭션의 독립성 병행해서 달리는 트랜잭션이 서로 독립된 것
Durability 데이터의 영속성 데이터가 영속하된 것. 영속화된 데이터를 읽어서 출력할 수 있는 것
원자성

시스템을 구축할 때는 원자성의 범위를 정해야 한다. 모든 처리가 실행됐는지, 실행되지 않았는지 트랜잭션을 정하는 것이다. 일반적으로 메서드에 들어가면서 트랜잭션 시작, 메서드를 빠져나오면서 트랜잭션 커밋처럼 결정한다.
 
트랜잭션 대상의 메서드가 모든 층에 흩어져 있으면 관리하기 어려우므로 일정한 규칙으로 트랜잭션의 시작과 종료가 이루어지는 메서드를 저앻야 한다. 이런 규칙으로 만들어진 트랜잭션의 시작과 종료는 논리적으로 레이어상의 선으로 나타나는데, 이것이 트랜잭션의 경계선이다.
 
경계선은 일반적으로 프레젠테이션 층과 비즈니스 로직 층 사이에 그어진다. 프레젠테이션 층에 공개된 비즈니스 로직 층의 서비스 클래스의 메서드가 트랜잭션의 시작이고 끝이다.
 
중요한 것은 트랜잭션의 경계를 만들기 위한 트랜잭션 구현을 어떻게 설계할 것인지이다.

선언적 트랜잭션

트랜잭션의 시작과 커밋, 롤백과 같은 RDB에 관한 트랜잭션 관리를 소스 코드로 명시하지 않고 정의 파일 등으로 선언해 프레임워크 등에서 제공되는 트랜잭션 처리에 트랜잭션 관리를 시킨다.
 
비즈니스 로직 층에 포함되는 컴포넌트를 자유롭게 조합할 수 있고, 오직 로직에만 전념할 수 있다. 아키텍처의 유연성을 높혀준다.
 
선언적 트랜잭션의 경계는 서비스 클래스의 메서드이다.

명시적 트랜잭션

RDB에 관한 트랜잭션 관리를 소스 코드로 명시한다.
 
프레젠테이션 층의 컨트롤러로 트랜잭션을 구현하여 비즈니스 층에 포함되는 컴포넌트는 트랜잭션으로부터 자유로워야 한다. 또한 트랜잭션의 관리가 한 곳에서 이루어져야 한다.
 
가장 나쁜 패턴은 로직 층에 포함되는 여러 클래스가 java.sql.Connection을 다루고 트랜잭션을 관리하는 것이다.


데이터 액세스 층의 역할

RDB 액세스를 비즈니스 로직에서 숨기고, 비즈니스 로직에 필요한 데이터를 테이블에서 취득해서 오브젝트에 매핑한다.

O/R 매핑

Object에서 Relational로 매핑하는 O/R 매핑은 객체 지향 분석을 통해 클래스를 추출하고 이를 바탕으로 설계 단계에서 테이블을 작성한다. 이 클래스 오브젝트 하나가 테이블의 레코드 하나에 대응한다. 객체 지향으로 분석 * 설계하면 일반적으로 이러한 O/R 매핑이 된다.
 
R에서 O로 매핑하는 R/O 매핑은 DOA(Data oreinted Approach)등에서 처리해 테이블을 작성할 경우나 시스템 개발 이전에 테이블이 이미 존재할 경우에 사용한다.
 
단순 입출력 애플리케이션인 경우 화면에 표시할 데이터를 모아서 한 오브젝트로 만드는 것이 효율적이므로 R/O 매핑을 선택할 수도 있다.

액세스 프레임워크의 종류

흔히 알려진 것은 ORM이다. XML 등으로 기술된 매핑 파일로, 오브젝트와 테이블을 매핑한다. 매핑 파일 작성은 손이 많이 가지만 SQL 문을 작성하지 않아도 된다는 특징이 있다. 이 ORM의 대표적인 프레임워크가 하이버네이트이다.
 
반면 SQL문 사용을 전제로한 액세스 프레임워크도 있는데, 스프링 JDBC나 MyBatis 등이 있다.

데이터 액세스 층의 설계 지침

데이터 액세스 층의 구현은 O/R인지 R/O인지에 따라 달라진다. R/O 매핑으로도 테이블 구조가 복잡하면 스프링 JDBC처럼 직접 SQL을 이용하는 방법도 생각해볼 수 있다. 설계 시 고려해야 하는 내용은 다음과 같다. 이는 데이터 액세스 프레임워크에 포함되어 있다.

커넥션 풀링을 이용한다

커넥션을 이용할 때마다 생성하고 해제하는 것은 효율적이지 않다. 일정량의 커넥션을 미리 생성시켜 저장소에 저쟁핬다가 요청이 있을때 커넥션을 꺼내 제공한다면 시간을 절약할 수 있다.

RDB가 바뀌어도 구현에 영향을 미치지 않게 한다

일반적으로 프레임워크에서 RDB를 설정 파일에서 지정하므로 RDB가 바뀌어도 구현에 영향을 미치지 않는다.

이용하는 RDB에 의존적인 SQL 문을 기술하지 않는다.

ORM에서는 설정 파일로 지정한 RDB에 의해 출력되는 SQL 문이 자동으로 변횐된다. 직접 SQL 문을 기술하는 방식의 DB 액세스 프레임워크에서는(R/O 매핑할 때 등) RDB에 의존하는 SQL 문을 기술하지 않도록 해야한다. 특히 주의해야할 것은 자동 증가 프라이머리 키 생성 방법과 현재 날짜 등을 구하는 함수 등이 RDB에 의존하는 기능이다.
 

DB 액세스 프레임워크에 존재하므로 데이터 액세스 층에는 설계할 곳이 거의 없다. 인터페이스(테이블과 도메인의 관계, 즉 O/R 매핑 부분)만 설게하면 된다. 테이블과 도메인의 설계가 끝나면 그 시스템의 특징과 필요한 성능을 얻을 수 있는 DB 액세스 프레임워크를 선택하면 된다.
 

비즈니스 로직 층과 데이터 액세스 층의 분리

아직 비즈니스 로직 층과 데이터 액세스 층의 상호 의존을 없앤 오목형 레이어에는 아직 문제가 남아있다.     일반적인 설계로는 비즈니스 로직 층에서 커넥션(세션)을 취득해 데이터 액세스 층에 전달하는 인터페이스가 되는데, 이는 데이터 액세스 층이 비즈니스 로직 총에 의존하게 된다. 인터페이스로부터 커넥션을 분리하는 방법은 스프링을 사용해 간단히 할 수 있다.
 
스프링은 레이어의 어느 곳에도 들어가지 않는 독립된 파티션이다.

부품화

부품이 큰 쪽은 티어나 레이어가 되고 그보다 작은 부품은 패키지나 컴포넌트가 된다. 그리고 부품끼리는 인터페이스로 연결된다. 티어나 레이어처럼 큰 부품은 컴퓨터의 본체, 모니터, 스피커에 해당된다면 패키지나 컴포넌트는 CPU, 메모리 등이 된다. 클래스는 메인보드, CPU 및 메모리에 들어가는 더 작은 부품이 된다.    
부품화는 인터페이스가 중요하다. 부품은 반드시 콘센트나 모듈러 잭 같은 인터페이스로 연결된다. 애플리케이션도 인터페이스로 연결할 수 있게 부품화할 수 있을 것이다. 스프링은 부품화 아키텍처를 만드는 데 아주 유용한 프레임워크이다.
 
부품화 하는 데 있어 가장 중요한 두가지가 있다.
첫째, 2개의 부품이 있을 때, 인터페이스를 어느 쪽이 가져야 하는지 결정해야 한다. 전자 제품의 인터페이스를 꽂을 구멍이 있는 쪽, 자바로 말하면 인터페이스의 정의가 있는 쪽이 어느 부품인가이다.
 
더 중요한 부품(컴퓨터 » 마우스)이 인터페이스를 가진다. 중요한 쪽이 인터페이스를 가져야 하지만 인퍼테이스가 필요 없어도 되는 곳에 불필요한 인터페이스를 붙이지 않아도 된다.
 
둘째는 어느 정도까지 부품화를 해야 하는가이다. 절대적인 기준은 없으며 부품화할 필요가 있는 만큼 부품화한다가 정답이다. 데스크톱도 일체형이 있다. 애플리케이션도 마찬가지이다.
 
부품화가 어렵다면 3레이어부터 시작하는 것이 좋다.


웹 애플리케이션이 안고 있는 문제

스프링을 이용하지 않을 떄의 문제점, 스프링을 이용하면 해결할 수 있는 문제점을 밝히고 가야 한다.

EJB의 문제(현재는 문제점이 해결됨)

EJB도 3.0 이후로 DI 컨테이너 AOP 프레임워크이므로 지금은 해당되지 않는다. 또한 중량 컨테이너인 EJB의 안티태제로 등장한 스프링은 거대해져 오히려 비교 대항이 Java EE가 됐다.

오브젝트의 생명 주기

프레젠테이션 부분에 서블릿을 컨트롤러로 한 MVC2 모델을 채용하는 것이 일반적이다. 서블릿은 View에 액세스하는 사용자 수가 증가할 때마다 인스턴스화에 의한 가비지 컬렉션의 성능 저하나 메모리 압박을 방지하도록 멀티스레드로 동작시키고 있다.
 
하지만 서비스 로직의 오브젝트를 매번 인스턴스화하게 구현하면 View에 액세스하는 사용자 수가 늘어남에 따라 인스턴스가 증가해 메모리 압박 등 성능면에서 문제가 된다. 이를 방지하려면 서비스 로직의 오브젝트는 싱글턴으로 해야 하지만, 이에 따라 구현 변경, 싱글턴일 필요가 없어졌을 때의 비용 증가 문제가 있다.
 
마찬가지로 오브젝트가 HTTP의 세션인 동안만 있으면 된다거나, Request일 때만 있으면 되는, 오래 살아남으면 곤란한 오브젝트의 생명주기를 만들어내는 것도 어렵지만, 스프링은 이러한 생명 주기도 관리해준다.

부품와의 문제

인터페이스를 적극적으로 활용하면 이용하는 쪽이 인터페이스가 확장, 변경되더라도 아무런 영향을 받지 않고, 또한 인터페이스 배후에 있는 오브젝트가 미완성이라도 mock으로 치환하여 진행할 수 있으므로 전자 제품처럼 부품별로 개발 거점을 나누어 작성할 수 있다.
 
하지만 단순히 인터페이스를 이용하는 것만으로 구현 비의존을 실현할 수 없다. 보통 구현 비의존을 실현하려면 팩토리 패턴을 적용하여 실현한다.

팩토리 패턴을 활용한 구현 비의존 실현 예

그러나 현실에서는 의존과 비의존을 만들어나가는 것 자체를 모르거나 비용아 많이 발생한다고 여기는 경우가 많다. 스프링을 사용하면 이 구현 비의존을 쉽게 실현할 수 있다.

기술 은닉과 부적절한 기술 은닉

고급 기술을 초보 개발자에게 이용하게 해서 장해를 일으키거나, 부적절한 기술 은닉으로 기술 이용을 어렵게 하는 문제도 흔히 볼 수 있다.

기술을 은닉하지 않아 발생한 문제 * 트랜잭션 제어를 초보자에게 코딩시켜 통합 테스트에서 트랜잭션 오류가 빈발했다.
* 예외 처리 순서가 인식되지 않아서 컴포넌트 사이의 어딘가에서 예외가 사라지는 이벤트가 운영 전에 발견돼 큰 문제가 됐다.
부적절하게 기술을 은닉한 문제 트랜잭션 제어를 개발자에게 은닉하고자 프레임워크를 만들었지만, 이용 절차가 복잡해서 동료들이 알기 어렵다고 외면했다.

문제 해결은 스프링에게 맡기자

위의 문제들을 해결하지 못한 웹 애플리케이션은 리소스를 잘 이용하지 못하고, 테스트하기 어려우며, 확장이나 변경도 어려워진다. 스프링은 다음처럼 위의 문제를 해결해줄 수 있다.

  • 오브젝트의 생명 주기 문제는 DI 컨테이너로 해결
  • 부품화 문제는 DI 컨테이너로 해결
  • 기술 은닉과 부적절한 기술 은닉 문제는 AOP로 해결

부품화의 미래

지금까지 이야기한 부품화는 모놀리식 형태를 대상으로 했다. 모놀리식은 웹 애플리케이션이 하나의 프로젝트 형태로 디플로이된 형태이므로, 한 부품을 수정하더라도 전체를 다시 디플로이해야 한다. 이는 부품화의 의미를 흐리게된다.

모놀리식 아키텍처

이로 인해 부품을 개별로 작성, 수정해서 디플로이할 수 있다고 생각한 마이크로서비스가 나왔다. 특정한 비즈니스 용건에 특화한 단위로서, 부품안에 UI부터 DB의 액세스까지 포함해도 문제가 되지 않는다. 이렇게 잘라낸 부품은 서비스(비즈니스 로직 층의 서비스와 다른 개념)라고 한다.
 
서비스를 하나의 프로덕트로 생각해서 팀별로 분담해서 개발하고, 구성된 서비스를 REST 등 경량의 통신 수단을 활용하여 유연하게 결합한 시스템을 만들어가는 것이 마이크로서비스 아키텍처이다.
 
스프링은 스프링 부트를 통해 마이크로서비스 아키텍처에 대응한다.


스프링 개요

여기서 스프링은 DI 컨테이너와 AOP 등을 구현하는 스프링 프레임워크를 의미한다.

스프링이란?

Java/Java EE용 프레임워크이다. DIxAOP 컨테이너를 중심으로 MVC 프레임워크(스프링 MVC, 스프링 웹 플로), JDBC를 추상화한 프레임워크(스프링 JDBC), 기존 프레임워크와의 통합 기능 등을 개발자에게 제공하는 애플리케이션 아키텍처의 기반이다.

프레젠테이션 층

스프링 MVC

프렌젠테이션 층에서는 스프링 MVC와 스프링 웹 플로를 이용할 수 있다. 이를 활용하면 Ajax 등의 연계도 가능하다.

스프링 시큐리티

정확하게는 프레젠테이션 층, 비즈니스 층, 데이터 액세스 층 전체에서 사용할 수 있지만, 프레젠테이션 층의 화면별 액세스 제어에 많이 사용된다.
 
인증/인가 기능을 제공하며, 베이직 인증이나 OAuth(PC, 모바일 단말기 등에서 안전하고 공개적인 프로토콜)의 표준에 따라가는 인증 서비스(Facebook, Twitter, Google 등)를 사용할 수 있다.

비즈니스 로직 층

스프링의 핵심이 되는 DIxAOP 컨테이너와 스프링 캐시를 알아본다. 둘 모두 정확하게는 복수의 레이어를 넘어서 사용할 수 있다.

스프링 DIxAOP 컨테이너

스프링을 특정짓는 기능이다. DI는 오브젝트를 생성하고 오브젝트끼리의 관게를 생성해 소프트웨어의 부품화 및 설계를 가능하게 한다. 인터페이스 기반의 컴포넌트를 쉽게 구현할 수 있게된다.
 
AOP를 이용하면 오브젝트 책임 외의 로직(사용자 인증, 트랜잭션 관리, 예외 처리 등)을 소스 코드에 명시적으로 기술하지 않고 나중에 추가할 수 있다. 이에따라 개발자는 비즈니스 로직에 집중할 수 있어서 코드가 한결 간결해지고 보기에도 쉬워진다.
 
AOP를 통해 책임 이외의 로직이 없어지면 DI를 이용한 컴포넌트화를 더 추진할 수 있고 단위 테스트나 팀 개발이 쉬워져 시스템 개발 비용을 크게 절감할 수 있다.

스프링 캐시

이용자 수가 늘어날수록 성능 문제가 발생할 수 있는데, 데이터를 캐시해서 RDB처리 횟수를 줄여 성능 문제를 개선한다.

데이터 액세스 층

스프링 JDBC

SQL 문을 이용하는 형태의 데이터 액세스 프레임워크이다. SELECT 문과 SELECT한 결과와 엔티티 클래스의 매핑을 기술하기만 하면 된다.

스프링 데이터

RDB와 NoSQL와 같이 서로 다른 데이터 스토어에 액세스하는 것을 통일화, 단순화를 목적으로 한 프로덕트이다. RDB에 대해서는 JPA, NoSQL에 대해서는 도큐먼트형 DB인 MongoDB, 그래픽 DB인 Neo4j 등이 액세스할 수 있다.
 
다른 데이터 액세스 통일화에 대해서는 아직 완전하게 대응되지 못했다.
지원하는 모듈 리스트

스프링 ORM 인티그레이션 기능

데이터 액세스 층에서 반드시 스프링 JDBC를 이용할 필요는 없다. 이 기능을 이용하면 하이버네이트 등을 간단히 이용할 수 있다. 스프링의 ORM 인티그레이션 기능을 이용하면 각각의 프레임워크를 단독으로 이용하는 것보다 간단하게 서비스를 만들 수 있다.
 
최근 ORM 프레임워크에도 새로운 프레임워크에 대한 인티그레이션 기능이 있어, 이 기능은 예전보다 유용성은 떨어졌지만, 오래된 프레임워크나 하이버네이트를 이용하는 경우라면 여전히 중요하고 유용한 기능이다.

스프링 배치

실제 시스템 개발에서 대량의 데이터의 일괄처리와 복수 처리, 병행 처리의 실행을 반드시 고려한 배치 처리가 필요하다. 이러한 배치 처리를 실행하기 위한 템플릿이 스프링 배치이다.

스프링 부트

소프트웨어 개발을 위한 기반 프레임워크라고도 말할 수 있다. 스프링 기술 뿐만 아니라 그 밖의 라이브러리를 적절하게 통합한 템플릿을 풍부하게 제공하고 있어서, 웹 애플리케이션을 빠르게 개발할 수 있게 해준다.

스프링을 사용하는 이유

실질적이 아닌 실제 표준인 Java EE는 실질적 표준인 스프링의 영향을 많이받았다. 앞으로도 Java EE는 스프링을 따라갈 것이다.
 
Java EE보다 대응하는 범위가 넓다. 다음 시대를 예견하는 마이크로서비스 아키텍처와 클라우드 네이티브의 애플리케이션은 스프링 부트만한 것이 없다.

tag: spring

Related Posts