스프링은 주로 자바 엔터프라이즈 환경에서 동작하는 애플리케이션을 개발하는데에 사용된다.
즉, 클라이언트의 요청을 받아 작업을 수행하고 그 결과를 반환하는 형식으로 서비스를 제공한다.
스프링이 사용되는 애플리케이션의 기본구조
클라이언트가 웹 브라우저여야 하는 것도 아니며 백엔드 시스템은 DB를 이용해야 하는 것만은 아니다.
자바 서버가 받아들일수 있는 방식으로 요청을 보내기만 한다면 어떤 종류의 클라이언트이든 상관없다.
스프링 엔터프라이즈 애플리케이션은 DB는 물론 메시징 서버, 메일 서버 등 자바가 지원하는 접속방식을 제공하기만 하는 시스템이면 백엔드 시스템으로 이용할 수 있다.
스프링으로 만든 애플리케이션을 자바 서버환경에 배포하려면 JavaEE 서버가 필요하다.
JavaEE의 대부분의 표준 기술을 지원하고 다양한 형태의 모듈로 배포 가능한 완전한 웹 애플리케이션 서버(WAS)
웹 모듈의 배포만 가능한 경량급 WAS또는 서블릿/JSP 컨테이너
스프링은 기본적으로 톰캣이나 제티 같은 가벼운 서블릿 컨테이너만 있어도 충분하다.
서블릿 컨테이너로도 엔터프라이즈 애플리케이션에 필요한 핵심기능을 모두 이용할 수 있다.
라이브러리의 도움을 받는다면 분산/글로벌 트랜잭션도 사용할 수 있다.
미션 크리티컬한 시스템 에서 요구하는 고도의 안정성이나 고성능 시스템에서 안정적인 리소스 관리등 필요가 있다면 상용/오픈소스 WAS를 이용할 수 있다.
상대적으로 관리 기능이나 모니터링이 기능이 뛰어나서 여러 대의 서버를 동시에 운영할 때 유리한 점이 많다.
미션 크리티컬한 시스템?
비즈니스 또는 조직의 생존에 필수적인 시스템
업무 수행을 위하여 가장 중요한(필수 불가결한) 요소
- 국방·의료·금융·반도체·우주항공 등처럼 작은 실수만으로도 치명적인 결과를 초래하는 분야를 말한다.
- IT 영역에서는 통신 시스템, 재난 통신망, 항공 관제시스템, 데이테이스 시스템 등을 미션 크리티컬 요소로 본다.
톰캣 기반으로 엔터프라이즈 스프링 애플리케이션에 최적화된 경량급 서버
기존 톰캣에서는 아쉬웠던 고급 서버 관리 기능, 배포 기능, 진단 기능을 포함 톰캣 전문가의 기술지원까지 제공 받을 수 있다.
스프링 개발회사가 개발한 것이라 애플리케이션 개발 및 운영에 필요한 중요한 기능을 제공받을 수 있다.
JAR, WAR, EAR 차이점
JAR, WAR, EAR 파일의 가장 큰 차이점은 서로 다른 환경을 대상으로한다는 점이다.
- EAR 파일을 실행하려면 완전한 Java EE (Java Platform, Enterprise Edition) 또는 JBoss와 같은 Jakarta Enterprise Edition (EE) 호환 애플리케이션 서버가 필요하다.
- WAR 파일은 Java EE Web Profile 호환 응용 프로그램 서버 만 실행하면되고 JAR 파일은 Java 설치 만 필요하다.
스프링3.0 을 적용하기 위해서는 jdk6.0, 적어도 5.0이상을 사용해야한다.
J2EE 1.4나 javaEE 5.0이상이 필요하다.
프로젝트 폴더 구조와 라이브러리 선정을 스스로 결정해야 하는 상황이라면 신경써야 할게 많다.
스프링 모듈
라이브러리
Build라는 동적인 요소를 XML로 정의하기에는 어려운 부분이 많다.
아키텍처는 내부 구성요소들이 어떤 책임을 갖고 어떤 방식으로 서로 관계를 맺고 동작하는지 규정하는 것이라고 할 수 있다.
성격이 다른 모듈이 강하게 결합되어 한데 모여 있으면 한 가지 이유로 변경이 일어날 때 그와 상관없는 요소도 함께 영향을 받게 된다.
인터페이스와 같은 유연한 경계를 만들어두고 분리하거나 모아주는 작업이 필요하다.
이런 원리는 아키텍처 레벨에서 좀 더 큰 단위에 대해서도 동일하게 적용할 수 있다.
애플리케이션을 구성하는 오브젝트들을 비슷한 성격과 책임을 가진 것들끼리 묶을 수 있다.
이렇게 성격이 다른 것은 아키텍처 레벨에서 분리해주는 게 좋다.
보통 웹 기반의 엔터프라이즈 애플리케이션은 일반적으로 세 개의 계층을 갖는다고해서 3계층 애플리케이션이라고 한다.
잘 만들어진 스프링 애플리케이션의 서비스 계층 클래스는 이상적인 POJO로 작성된다.
POJO로 만든다면 객체지향적인 설계 기법이 적용된 코드를 통해서 비즈니스 로직의 핵심을 잘 담아내고, 이를 쉽게 테스트하고 유연하게 확장할 수 있다.
POJO?
- POJO는 "Plain Old Java Object"의 약자로, 간단하고 오래된 방식으로 작성된 자바 객체를 의미한다..
- POJO는 특정 프레임워크나 라이브러리에 종속되지 않는 순수한 자바 객체를 뜻한다.
프레젠테이션 계층은 가장 복잡한 계층이다. 프레젠테이션 계층은 매우 다양한 기술과 프레임워크의 조합을 가질 수 있다.
프레젠테이션 계층은 다른 계층과 달리 클라이언트까지 그 범위를 확장될 수도 있다.
엔터프라이즈 시스템은 본질적으로 동시에 많은 작업이 빠르게 수행돼야 하는 시스템이다.
데이터 중심구조의 특징은 하나의 업무 트랜잭션에 모든 계층의 코드가 종속되는 경향이 있다는 점이다.
예를 들어 사용자의 이름으로 사용자 정보를 검색해서 일치하는 사용자의 아이디, 비밀번호, 이름 등을 보여주는 작업이 있다고 하자.
이것이 하나의 업무 단위가 되면 모든 계층의 코드가 이 기준에 맞춰서 만들어 진다.
사용자 조회라는 단위 업무를 위해서만 존재하는 각 계층의 코드가 만들어진다는 뜻이다.
이런 식의 개발 방법과 아키텍처는 예전 엔터프라이즈 시스템에서 흔히 발견할 수 있다.
오브젝트 중심 아키텍처가 데이터 중심 아키텍처와 다른 특징은 도메인 모델을 반영하는 오브젝트 구조를 만들어두고 그것을 각 계층 사이에서 정보를 전송하는 데 사용한다는 것이다.
오브젝트 중심 아키텍처는 객체지향 분석과 모델링의 결과로 나오는 도메인 모델을 오브젝트 모델로 활용한다.
카테고리와 상품이라는 두가지 엔티티가 나오는 상황을 예를 들어 보자.
조건에 맞는 모든 카테고리와 상품 정보를 가져와서 화면에 출력하는 기능을 만든다고 할때, 데이터 중심 아키텍처에서는 SQL과 DB관점에서 생각한다.
JOIN문을 활용해 2차원 구조의 정보를 만들어 두 정보를 조합 할 수 있다.
SELECT c.categoryid , c.description, p.productid, p.name, p.price
FROM product p
JOIN category c on p.categoryid= c.categoryid
맵에 필드 이름과 값을 담아 결과를 저장할 수 있다.
while(rs.next()){
Map<String,Object> resMap = new HashMap<String, Object>();
resMap.put(“categoryid”,rs.getString(1));
resMap.put(“description“, rs.getString(2));
…
list.add(resMap);
}
서비스 계층에 전달되는 것은 List<Map<String, Object>>
타입이다.
결과를 사용하는 서비스 계층이나 프레젠테이션 계층의 코드에서는 DAO메소드에서 두 개의 테이블을 JOIN
을 사용해 필드의 값을 가져와 필드 이름을 키로 갖는 맵에 값을 저장했음을 알아야 사용할 수 있다.
DAO에서 SQL을 변경하거나 필드 개수나 순서, 이름을 바꾼다면 서비스 계층과 프레젠테이션 계층의 코드도 같이 변경돼야 한다.
반면에 오브젝트 중심 아키텍처 에서는 애플리케이션에서 사용되는 정보가 도메인 모델의 구조를 반영해 만들어진 객체 안에 담긴다.
도메인 모델은 애플리케이션 전 계층에서 동일한 의미를 갖는다.
도메인 오브젝트
public class Category{
int categoryid;
String description;
Set<Product> products; // 여러개의 Product를 참조하고있는 컬렉션을 가질수 있다.
…
}
public class Product{
int productid;
Stringname;
int price;
Category category; // 1개의 Category를 가리키는 레퍼런스를 직접 갖고 있다.
…
}
자바의 레퍼런스 개념은 상호 참조가 가능 하게 한다.
애플리케이션 어디에서도 사용될 수 있는 일관된 형식의 도메인 정보를 담고 있다.
Category 오브젝트에서 Category에 속한 Product를 가져올 수도 있다.
Set<Product> products = myCategory.getProducts();
데이터 중심 방식에서는 Category와 그에 대응되는 Product를 찾아 SQL을 이용해 조인한 다음 하나의 맵에 뭉뚱그려서 가져왔다.
오브젝트 중심 방식에서는 테이블의 정보과 그 관계를 유지한 채로 정확한 개수의 Category 객체와 그에 대응되는 Product 객체로 만들어 사용할 수 있다.
최적화된 SQL을 매번 만들어 사용하는 경우에 비해 성능 면에서 조금은 손해를 감수해야 할 수도 있다.
DAO는 비즈니스 로직의 사용 방식을 알지 못하므로, 도메인 오브젝트의 모든 필드 값을 다 채워서 전달하는 경우가 대부분이다.
일단 최소한의 오브젝트 정보만 읽어두고 관계하고 있는 오브젝트가 필요한 경우에만 다이내믹하게 DB에서 다시 읽어올 수 있다.
도메인 오브젝트를 사용하는 오브젝트 중심 아키텍처에서는 가능하다면 ORM과 같은 오브젝트 중심 데이터 액세스 기술을 사용하는 것을 권장한다.
지연된 로딩
- 데이터를 실제로 로딩하는 시점을 필요한 시점으로 지연 시키는 기법
- 데이터를 조회할 때 데이터베이스에서 필요한 데이터만을 가져오는 것을 의미
도메인 오브젝트에 정보만 담겨 있고, 정보를 활용하는 기능이 없다면 이는 온전한 오브젝트라고 보기 힘들다.
이런 오브젝트를 빈약한(anemic) 오브젝트라 부른다.
도메인 모델을 반영한 오브젝트에 정보를 담아 활용하는 편이 도메인 오브젝트를 사용하지 않는 것보다는 훨씬 낫다.
도메인 오브젝트에 넣을 수 있는 기능
도메인의 비즈니스 로직
빈약한 도메인 오브젝트 방식에서는 비즈니스 로직이 서비스 계층에 있다.
도메인 오브젝트 방식은 거대한 서비스 계층구조와 비슷하다.
비즈니스 로직이 복잡하지 않다면 가장 만들기 쉽고 3계층 구조의 특징을 잘 살려서 개발할 수 있는 유용한 아키텍처다.
빈약한 도메인 오브젝트의 단점을 극복하고 도메인 오브젝트의 객체지향적인 특징을 잘 사용할 수 있도록 개선
어떤 비즈니스 로직은 특정 도메인 오브젝트나 그 관련 오브젝트가 가진 정보와 깊은 관계가 있다.
이런 로직을 서비스 계층의 코드가 아니라 도메인 오브젝트에 넣어주고, 서비스 계층의 비즈니스 로직에서 재사용하게 만드는 것이다.
EX) 앞에서 만든 Category에 해당하는 Product의 가격을 모두 합하는 로직을 굳이 서비스 계층에 두지않고 Category 도메인 오브젝트에 로직을 담을 수 있다.
도메인 오브젝트에 비즈니스 로직을 넣는다고 해서 비즈니스 로직을 담고 있던 서비스 계층 오브젝트가 필요 없어지는 건 아니다.
- 도메인 오브젝트는 직접 데이터 액세스 계층이나 기반 계층 또는 다른 서비스 계층의 오브젝트에 접근할 수 없기 때문에 서비스 계층이 필요하기도 하다.
도메인 계층의 역할과 비중을 극대화하려다 보면 기존의 풍성한 도메인 오브젝트의 방식으로는 만족할 수 없다.
도메인 객체가 기존 3계층과 같은 레벨로 격상되어 하나의 계층을 이루게 하는 것이 도메인 계층 방식이다.
도메인 객체 독립된 계층을 다음과 같은 특징을 갖게 된다.
도메인에 종속적인 비즈니스 로직의 처리는 서비스 계층이 아니라 도메인 계층의 오브젝트 안에서 진행된다.
도메인 객체가 기존 데이터 접근 계층이나 기반 계층의 기능을 직접 사용할 수 있다.
스프링이 관리하지 않는 도메인 오브젝트에 DI를 적용하기 위해서는 AOP가 필요하다.
도메인 계층 방식은 이전의 어떤 방식보다 도메인 객체에 많은 비즈니스 로직을 담아낼 수 있다.
때로는 여러 도메인 오브젝트의 기능을 조합해서 복잡한 작업을 진행해야 하는 경우가 있다.
도메인 오브젝트가 계층을 이루기 전에는 모든 계층에 걸쳐 사용되는 일종의 정보전달 도구 같은 역할을 했다.
도메인 오브젝트가 도메인 계층을 벗어나서도 사용되게 할지 말지 결정해야 한다.
여전히 모든 계층에서 도메인 오브젝트를 사용한다.
다양한 기능을 가진 도메인 객체를 프레젠테이션 계층이나 뷰 등에서 사용하게 해주면 이를 함부로 사용하는 위험이 따를 수 있다.
철저한 가이드라인을 만들어두고 이를 적용해야한다.
도메인 오브젝트는 도메인 계층을 벗어나지 못하게 할 수도 있다.
도메인 계층 밖으로 전달될 때는 별도로 준비된 정보 전달용 객체(DTO)dp 도메인 객체 내용을 복사해서 넘겨준다.
DTO는 기능을 갖지 않으므로 사용하기에 안전하다.
프레젠테이션 계층의 코드가 서버에서 클라이언트로 다운로드 되어 클라이언트 장치 안에서 동작하며 서버에 존재하는 프레젠테이션 계층이나 서비스 계층과 통신하는 구조
아키텍처 설계에서 한 가지 더 신경 써야 할 사항은 상태 관리다.
애플리케이션은 하나의 HTTP 요청의 범위를 넘어서 유지해야 하는 상태정보가 있다.
엔터프라이즈 애플리케이션은 특정 사용자가 독점해서 배타적으로 사용되지 않는다.
하나의 애플리케이션이 동시에 수많은 사용자의 요청을 처리하게 하기 위해 매번 간단한 요청을 받아서 그 결과를 돌려주는 방식으로 동작한다.
서버의 자원이 특정 사용자에게 일정하게 할당되지 않는다.
서버 기반의 애플리케이션은 원래 지속적으로 유지되는 상태를 갖지 않는다(stateless)는 특징이 있다.
어떤 식으로든 애플리케이션의 상태와 장시간 진행되는 작업정보는 유지돼야 한다.
스프링은 기본적으로 상태가 유지되지 않는 빈과 객체를 사용하는 것을 권장한다.
웹 클라이언트에 URL, 파라미터, 폼 히든 필드, 쿠키 등을 이용해 상태정보 또는 서버에 저장된 상태정보에 키 값 등을 전달할 수 있다.
웹 클라이언트에 폼 정보를 출력하고 이를 수정하는 등의 작업을 위해서는 HTTP 세션을 적극 활용할 수 있다.
싱글톤 이외의 스코프를 갖는 빈을 만들어 독립적으로 생성되고 유지되는 객체를 사용해 상태를 저장하고 DI를 통해 서비스 계층에서 사용할 수 있게 할 수 있다.