javaee6 - 설계 차원의 단순성

4
out.close(); } } 기본 생성자 (default constructor)를 포함해야 한다는 것 이외에 주입된 클래스에 대한 특정한 요구 사항은 없다. public class Hello { public String helloWorld(){ return “Hello World”; } } 이에서 제시된 예제가 실행되도록 하기 위해서는 다음과 같은 컨텐츠를 포함하고 있는 빈 상태의beans.xml deployment descriptor도 필요할 것이다:<beans></beans>. WEB-INF 폴더 내에 이러한 구성 파일이 있 는 경우, CDI 기능이 활성화된다. Hello 클래스는 POJO이며, EJB가 아니라는 점을 유념해야 한다. 이는 선언되거나 구성될 필요가 없으며 @Inject 어노테이션은 적절한 생성과 라이프사이클 관리가 이루어지도록 한다. 실제 운영 환경에서는 POJO서블릿에 주입하는 경우는 극히 드물다. 아마도 UI 프레임워크( JSF 2같은)를 허용하거나 REST(Representational State Transfer)를 통해 서비스를 보여주는 방법을 선호할 것이다. 이와 같은 경우, CDI를 사용하 는 것이 훨씬 유용하다. 예를 들어, 데이터베이스 내에 메시지 문자열을 저장하는 간단한 MessageMe 애플리케이션을 생각해 보겠다. JSF 2 마크업(Markup) inputTextcommandButton 2개의 컴포넌트로 구성되어 있다. 리스팅 2에서와 같이inputText는 속성 메시지를 포함한 이름 색인을 가 진 클래스에 대한 value-bound 함수이며, 따라서 컨텐츠 속성을 가지고 있다. commandButtonsaction 속성은 이름 색인을 가진 backing beansave 메소드에 바인딩된다. 코드 리스팅 2: index.xhtml: CDI 내부 빈에 값 바인딩 <h:body> <h:form> Content:<h:inputText value=”#{index.message.content}”/> <br/> <h:commandButton value=”Save” action=”#{index.save}”/> </h:form> 2006년 발표된 Java Platform, Enterprise Edition (Java EE) 5은 엔 터프라이즈 애플리케이션 개발을 단순화하는데 크게 기여했다. 2009출시된 Java EE 6은 설계 및 아키텍처 작업을 더욱 쉽게 수행할 수 있 도록 했다. Java EE 6는 소규모의 상황적 애플리케이션(Situational applications)을 그 어떤 오버헤드 없이 신속하게 개발하는 데 적합한 옵 션이다. 이 글에서는 개발자들이 효율적이고 단순하며 손쉽게 유지 관리 할 수 있는 애플리케이션을 개발할 수 있도록 돕는 여러 다양한 Java EE 6 아키텍처와 설계 접근 방식에 대해 설명한다. Java EE 6Java EE의 이름으로 함께 릴리즈 된 일련의 독립 API로 구 성되어 있다. 이들 API는 독립적이지만, 놀라울 만큼 서로 긴밀하게 연 동된다. 하나의 애플리케이션에서 오직 JavaServer Faces (JSF) 2.0을 이용할 수 있거나, 트랜잭션 서비스를 위해 Enterprise JavaBeans (EJB) 3.1을 이용할 수 있거나, 아니면 Java Persistence API (JPA) 2.0 Bean Validation 모델을 채용한 CDI(Contexts and Dependency Injection)를 이용하여 트랜잭션을 이행할 수 있다. 상용 Java EE 6 API를 실용적으로 혼용하여 애플리케이션 내 트랜잭션, 스레딩 (Threading), 스로틀링 (Throttling) 또는 모니터링 등과 같은 인프 라 서비스를 구현해야 하는 필요성을 완전히 제거할 수 있다. 오버헤드와 복잡성을 최소화하고 커스텀 코드를 이용해서 모든 기본적인 요소들을 새 로 개발할 필요가 없도록 하는 최적 API 하위 집합을 선택하는 것은 결코 쉽지 않다. 일반적으로,대안을 찾기 위해 검토 범위를 확대하기 전에 기존 Java SE Java EE 서비스를 사용하기위해모든 노력을해야 한다. CDI: 표준 글루 (glue) Java EE 6이 출시되면서 처음 소개된 CDIJava EE 6 규격의 여러 파트 를 위한 글루 기능을 수행하고 POJO (Plain Old Java Object) 빈의 라 이프사이클을 관리하며 DI(Dependency Injection)를 위한 type-safe 메커니즘을 사용한다. CDI는 또한, 이벤트, 인터셉터(Interceptor), 데 코레이터 (Decorators), 표준화된 확장 조건 (Standardized extension points), 서비스 프로바이더인터페이스 (Service provider interface) 과 같은 많은 강력한 기능을 선보였다. CDI자체가 새로운 개념이며 통합레이어 역활을 하도록 설계되었기 때 문에 이전의 기술들과 일부 중복된다. 비록 EJB 3.1 injection 또는 JSF managed bean을 직접 사용할 수 있지만, 가능한 CDI를 사용하는 것을 고려해야 한다. CDI는 더욱 강력할 뿐만 아니라, 단일 API를 이용함으로 써애플리케이션을 단순화할 수 있다. CDI는 어노테이션 (Annotation)을 이용하여 DI(Dependency Injection) 을 수행한다. 가장 중요한 어노테이션은 javax.inject.Inject이다. 리스 1에 있는 예제는 이 어노테이션이 POJO를 서블릿에 주입하는 데 사 용되는 방법을 보여주고 있다. 수행해야 하는 작업은 필드를 선언하고 @ Inject 어노테이션을 다는 것뿐이다. 이 코드가 실행되면 컨테이너는 비즈 니스 메소드가 실행되기 전에 @Inject 어노테이션이 달린 필드를 자동으 로 초기화한다. 코드 리스팅 1: @Inject으로 서블릿에 POJO 주입 @WebServlet(name=”HelloWorldService”, urlPatterns={“/ HelloWorldService”}) public class HelloWorldHTTPService extends HttpServlet { @Inject private Hello hello; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println(hello.helloWorld()); out.flush(); </h:body> 리스팅 3은 요청 처리를 위한 @RequestScoped를 이용해 request- scoped CDI 빈으로서 구현된 backing bean 을 보여준다. JSF 2 managed bean (@ManagedBean 어노테이션)을 사용할 수 있지만, CDI도 그만큼 강력하다. 또한, CDI를 사용하면, 모든 애플리케이션 레이 어 전반에 걸쳐 단일 글루 API를 적용하여 어디에서나 아키텍처를 단순화 할 수 있다. 코드 리스팅 3: 주입된 EJB을 포함한 CDI backing bean package com.abien.messageme.presentation; import com.abien.messageme.business.messaging.boundary. Messaging; import com.abien.messageme.business.messaging.entity. Message; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.inject.Named; @Named @RequestScoped public class Index { @Inject Messaging ms; private Message message = new Message(); public Message getMessage() { return message; } public void save(){ ms.store(message); } } 어노테이션 @Named (JSR 330 규격에 명시되고 Guice and Spring 에 구현된 바와 같이)은 색인 backing bean을 모든 EL(expression language) 마크업 형태로 나타낼 수 있도록 한다.이는 JSF 2 backing bean의 이름은 클래스 이름에서 추출한다는“CoC(Convention over Configuration)” 원칙을 따른다. 첫 글자에 대문자를 사용하지 않는다. Message 클래스는 리스팅 4에서와 같이 JPA 2 엔티티로 구현된다. 설계 차원의 단순성 : 새로운 Java EE 6 기능을 활용하여 단순하고 유지 관리하기 쉬운 애플리케이션 개발 저자 - Adam Bien 감수 - 이창제 Architect,OFM APAC Solutions & Technology Architects Technology & Developer 설계 차원의단순성 Spring 2011 64 65 Spring 2011 설계 차원의 단순성 Technology & Developer

Upload: jay-lee

Post on 07-Jul-2015

168 views

Category:

Technology


12 download

DESCRIPTION

JavaEE6 - 설계 차원의 단순성

TRANSCRIPT

Page 1: JavaEE6 - 설계 차원의 단순성

out.close();

}

}

기본 생성자(default constructor)를 포함해야 한다는 것 이외에 주입된

클래스에 대한 특정한 요구 사항은 없다.

public class Hello {

public String helloWorld(){

return “Hello World”;

}

}

이에서 제시된 예제가 실행되도록 하기 위해서는 다음과 같은 컨텐츠를

포함하고 있는 빈 상태의 beans.xml deployment descriptor도 필요할

것이다: <beans></beans>. WEB-INF 폴더 내에 이러한 구성 파일이 있

는 경우, CDI 기능이 활성화된다.

Hello 클래스는 POJO이며, EJB가 아니라는 점을 유념해야 한다. 이는

선언되거나 구성될 필요가 없으며 @Inject 어노테이션은 적절한 생성과

라이프사이클 관리가 이루어지도록 한다. 실제 운영 환경에서는 POJO를

서블릿에 주입하는 경우는 극히 드물다. 아마도 UI 프레임워크(JSF 2와

같은)를 허용하거나 REST(Representational State Transfer)를 통해

서비스를 보여주는 방법을 선호할 것이다. 이와 같은 경우, CDI를 사용하

는 것이 훨씬 유용하다.

예를 들어, 데이터베이스 내에 메시지 문자열을 저장하는 간단한

MessageMe 애플리케이션을 생각해 보겠다. JSF 2 마크업(Markup)

은 inputText와 commandButton 등 2개의 컴포넌트로 구성되어 있다.

리스팅 2에서와 같이 inputText는 속성 메시지를 포함한 이름 색인을 가

진 클래스에 대한 value-bound 함수이며, 따라서 컨텐츠 속성을 가지고

있다. commandButtons의 action 속성은 이름 색인을 가진 backing

bean의 save 메소드에 바인딩된다.

코드 리스팅 2: index.xhtml: CDI 내부 빈에 값 바인딩

<h:body>

<h:form>

Content:<h:inputText value=”#{index.message.content}”/>

<br/>

<h:commandButton value=”Save” action=”#{index.save}”/>

</h:form>

2006년 발표된 Java Platform, Enterprise Edition (Java EE) 5은 엔

터프라이즈 애플리케이션 개발을 단순화하는데 크게 기여했다. 2009년

출시된 Java EE 6은 설계 및 아키텍처 작업을 더욱 쉽게 수행할 수 있

도록 했다. Java EE 6는 소규모의 상황적 애플리케이션(Situational

applications)을 그 어떤 오버헤드 없이 신속하게 개발하는 데 적합한 옵

션이다. 이 글에서는 개발자들이 효율적이고 단순하며 손쉽게 유지 관리

할 수 있는 애플리케이션을 개발할 수 있도록 돕는 여러 다양한 Java EE 6

아키텍처와 설계 접근 방식에 대해 설명한다.

Java EE 6는 Java EE의 이름으로 함께 릴리즈 된 일련의 독립 API로 구

성되어 있다. 이들 API는 독립적이지만, 놀라울 만큼 서로 긴밀하게 연

동된다. 하나의 애플리케이션에서 오직 JavaServer Faces (JSF) 2.0만

을 이용할 수 있거나, 트랜잭션 서비스를 위해 Enterprise JavaBeans

(EJB) 3.1을 이용할 수 있거나, 아니면 Java Persistence API (JPA) 2.0

과 Bean Validation 모델을 채용한 CDI(Contexts and Dependency

Injection)를 이용하여 트랜잭션을 이행할 수 있다.

상용 Java EE 6 API를 실용적으로 혼용하여 애플리케이션 내 트랜잭션,

스레딩(Threading), 스로틀링(Throttling) 또는 모니터링 등과 같은 인프

라 서비스를 구현해야 하는 필요성을 완전히 제거할 수 있다. 오버헤드와

복잡성을 최소화하고 커스텀 코드를 이용해서 모든 기본적인 요소들을 새

로 개발할 필요가 없도록 하는 최적 API 하위 집합을 선택하는 것은 결코

쉽지 않다. 일반적으로, 대안을 찾기 위해 검토 범위를 확대하기 전에 기존

Java SE 및 Java EE 서비스를 사용하기 위해 모든 노력을 해야 한다.

CDI: 표준 글루(glue)

Java EE 6이 출시되면서 처음 소개된 CDI는Java EE 6 규격의 여러 파트

를 위한 글루 기능을 수행하고 POJO (Plain Old Java Object) 빈의 라

이프사이클을 관리하며 DI(Dependency Injection)를 위한 type-safe

메커니즘을 사용한다. CDI는 또한, 이벤트, 인터셉터(Interceptor), 데

코레이터(Decorators), 표준화된 확장 조건(Standardized extension

points), 서비스 프로바이더 인터페이스(Service provider interface) 등

과 같은 많은 강력한 기능을 선보였다.

CDI자체가 새로운 개념이며 통합레이어 역활을 하도록 설계되었기 때

문에 이전의 기술들과 일부 중복된다. 비록 EJB 3.1 injection 또는 JSF

managed bean을 직접 사용할 수 있지만, 가능한 CDI를 사용하는 것을

고려해야 한다. CDI는 더욱 강력할 뿐만 아니라, 단일 API를 이용함으로

써 애플리케이션을 단순화할 수 있다.

CDI는 어노테이션(Annotation)을 이용하여 DI(Dependency Injection)

을 수행한다. 가장 중요한 어노테이션은 javax.inject.Inject이다. 리스

팅 1에 있는 예제는 이 어노테이션이 POJO를 서블릿에 주입하는 데 사

용되는 방법을 보여주고 있다. 수행해야 하는 작업은 필드를 선언하고 @

Inject 어노테이션을 다는 것뿐이다. 이 코드가 실행되면 컨테이너는 비즈

니스 메소드가 실행되기 전에 @Inject 어노테이션이 달린 필드를 자동으

로 초기화한다.

코드 리스팅 1: @Inject으로 서블릿에 POJO 주입

@WebServlet(name=”HelloWorldService”, urlPatterns={“/

HelloWorldService”})

public class HelloWorldHTTPService extends HttpServlet {

@Inject

private Hello hello;

@Override

protected vo id doGet (Ht tpServ le tRequest request ,

HttpServletResponse response)

throws ServletException, IOException {

PrintWriter out = response.getWriter();

out.println(hello.helloWorld());

out.flush();

</h:body>

리스팅 3은 요청 처리를 위한 @RequestScoped를 이용해 request-

scoped CDI 빈으로서 구현된 backing bean을 보여준다. JSF 2

managed bean (@ManagedBean 어노테이션)을 사용할 수 있지만,

CDI도 그만큼 강력하다. 또한, CDI를 사용하면, 모든 애플리케이션 레이

어 전반에 걸쳐 단일 글루 API를 적용하여 어디에서나 아키텍처를 단순화

할 수 있다.

코드 리스팅 3: 주입된 EJB을 포함한 CDI backing bean

package com.abien.messageme.presentation;

import com.abien.messageme.business.messaging.boundary.

Messaging;

import com.abien.messageme.business.messaging.entity.

Message;

import javax.enterprise.context.RequestScoped;

import javax.inject.Inject;

import javax.inject.Named;

@Named

@RequestScoped

public class Index {

@Inject

Messaging ms;

private Message message = new Message();

public Message getMessage() {

return message;

}

public void save(){

ms.store(message);

}

}

어노테이션 @Named (JSR 330 규격에 명시되고 Guice and Spring

에 구현된 바와 같이)은 색인 backing bean을 모든 EL(expression

language) 마크업 형태로 나타낼 수 있도록 한다. 이는 JSF 2 내 backing

bean의 이름은 클래스 이름에서 추출한다는“CoC(Convention over

Configuration)” 원칙을 따른다. 첫 글자에 대문자를 사용하지 않는다.

Message 클래스는 리스팅 4에서와 같이 JPA 2 엔티티로 구현된다.

설계 차원의 단순성 :새로운 Java EE 6 기능을 활용하여 단순하고 유지 관리하기 쉬운 애플리케이션 개발

� 저자 - Adam Bien� 감수 - 이창제 Architect, OFM APAC Solutions & Technology Architects

Technology & Developer 설계 차원의 단순성 Spring 2011 64 65 Spring 2011 설계 차원의 단순성 Technology & Developer

Page 2: JavaEE6 - 설계 차원의 단순성

코드 리스팅 4: Bean Validation으로 검증된 JPA 2 엔티티

package com.abien.messageme.business.messaging.entity;

@Entity

public class Message {

@Id

@GeneratedValue

private Long id;

@Size(min=2,max=140)

private String content;

public Message(String content) {

this.content = content;

}

public Message() { /*required by JPA */}

public String getContent() {

return content;

}

public void setContent(String content) {

this.content = content;

}

public Long getId() {

return id;

}

}

이 예제의 다음 클래스는 Messaging 클래스로서 EJB 3.1 세션 빈

(Session bean)으로 구현되었다. 이 클래스는 “CDI everywhere” 규

칙의 실제적인 예외를 보여주고 있다. EJB는 트랜잭션, 풀링(Pooling),

Java Management Extensions (JMX) 모니터링 및 비동기식 실행 등

과 같은 많은 기능을 단지 @Stateless 어노테이션 하나만으로 제공할 수

있다. 향후의 Java EE 릴리스에서는 이들 aspect들이 EJB에서 추출되

고 CDI에서도 이용할 수 있게 될 것이다. 하지만, Java EE 6에서는 비즈

니스 컴포넌트의 바운더리(Boundary) 또는 퍼사드(Facade) 들이 무상

태 세션 빈(Stateless session bean)으로서 가장 효과적으로 구현된다.

리스팅 5의 @Asynchronous 어노테이션은 특히 흥미롭다. 이 어노테이

션은 메소드가 비동기이면서도 트랜젝션을 지원하는 메소드 실행을 지원

하며, 오직 EJB용으로만 이용할 수 있다. Messaging EJB 는@EJB가 아

닌 @Inject를 이용하여 주입된다는 점을 유념하라. 실제 업무에서 두 어노

테이션 모두 적용되며 거의 차이가 없다. @Inject의 사용이 약간 더 강력하

며 상속(inheritance)을 지원한다. 반면, @EJB 어노테이션은 오직 EJB에

서만 실행된다.

코드 리스팅 5: EJB 세션 빈으로서 구현된 바운더리

package com.abien.messageme.business.messaging.boundary;

import com.abien.messageme.business.messaging.control.

MessageStore;

import com.abien.messageme.business.messaging.entity.

Message;

import javax.ejb.Asynchronous;

import javax.ejb.Stateless;

import javax.inject.Inject;

@Stateless

public class Messaging {

@Inject

MessageStore messageStore;

@Asynchronous

public void store(Message message){

messageStore.store(message);

}

}

리스팅 6의 MessageStore 클래스는 EntityManager에 대한 액세스를

캡슐화한 DAO(Data Access Object)이다.

코드 리스팅 6: 컨트롤 레이어의 CDI 빈

package com.abien.messageme.business.messaging.control;

import com.abien.messageme.business.messaging.entity.

Message;

import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

public class MessageStore {

@PersistenceContext

EntityManager em;

public void store(Message message){

em.persist(message);

}

}

ECB: 실용적인 SoC(Separation of Concern)

위에서 설명한 애플리케이션의 패키징을 검토한다면, 별도의 바운더리,

컨트롤 및 엔티티 패키지를 확인하게 될 것이다. 이 패키징 접근 방식은

ECB(Entity Control Boundary) 패턴의 구현이다. 바운더리 레이어는 퍼

사드이며, 컨트롤 레이어는 프로세스 – 및 엔티티 – 독립적인 로직의 구

현을 담당한다. 그리고 엔티티 레이어는 많은 도메인 객체를 포함하고 있

다.

Java EE 6과 특히 JPA 2, CDI, 및 EJB를 이용할 수 있음에 따라 모든 3개

레이어의 구현은 빈 상태의 델리케이트(Delegate) 코드로 이어질 수 있

다. 예를 들어 많은 CRUD 기반 유스 케이스는 다수의 엔티티에 액세스하

는 퍼사드의 기능을 수행하는 단일 바운더리를 이용해서 매우 효율적으로

구현될 수 있다.

하지만, ECB 패턴 내 개념과 컴포넌트 내부 패키지 간의 직접적인 1대1 관

계가 여전히 효율적일 수 있다. 패키지가 계속해서 분리되어 있는 경우, 패

키지 간의 종속성을 측정하는 데 정적 분석 툴이 보다 쉽게 사용될 수 있

다. 뿐만 아니라, OSGi와 Jigsaw 등과 같은 프레임워크는 별도의 패키지

가 존재한다는 사실을 토대로 공용 API를 나타낸다.

Java EE 6에서 바운더리는 항상 EJB를 인식한다. 컨트롤 레이어는 CDI

또는 EJB 중 하나를 포함할 수 있으며 엔티티 레이어는 JPA 2 엔티티 또

는 transient, unmanaged 엔티티를 포함할 수 있다. 컨트롤 레이어 내

에서 CDI나 EJB 중 어떤 것을 사용할 것인지에 대한 결정을 반드시 사

전에 내릴 필요는 없다. CDI에서 시작하고 진행하면서 @Stateless 어노

테이션을 사용하여 EJB로 변환할 수 있다. @RequiresNew로 후속 트

랜잭션을 시작해야 할 때, 메소드를 비동기식으로 실행해야 할 때, 또는

SessionContext.setRollbackOnly()를 호출하여 현재의 트랜잭션을 롤

백시켜야 할 때 등 몇몇 경우에는 EJB를 사용해야 한다.

반면, CDI는 레거시 코드를 통합하거나 Strategy, Factory 또는

Observer 소프트웨어 설계 패턴을 구현하는 경우에 더욱 적합하다. 이들

기능 모두는 이미 기본 내장되어 있으며 따라서, Java SE의 기능을 이용

하는 경우보다 코드 수를 크게 줄일 수 있다.

ECB 패턴을 이용하여 애플리케이션을 개발하는 경우, ECB 레이어링은

반복적으로 전개해야 하며 하향식(Top-down)으로 강제되어서는 안된

다. 영속성 (Entity) 레이어에서 시작하고 단위 테스트(Unit testing)를 수

행한 다음 바운더리 레이어를 구현해야 한다. 단위 테스트를 개발하기 위

해 EntityManager와 관련 트랜잭션을 수작업으로 생성하고 관리해야 한

다(리스팅 7 참조).

코드 리스팅 7: 단독형 JPA 단위 테스트

package com.abien.messageme.business.messaging.entity;

import javax.persistence.*;

import org.junit.Test;

@Test

public void mappingSmokeTest() {

EntityManagerFactory emf = Persistence.createEntityManage

rFactory(“test”);

EntityManager em = emf.createEntityManager();

EntityTransaction tx = em.getTransaction();

tx.begin();

em.persist(new Message(“duke”));

tx.commit();

}

persistence.xml 파일도 단독 실행을 처리하도록 수정되어야 한다. 특

히, 트랜잭션 유형을 RESOURCE_LOCAL로 변경해야 하며 JDBC 커넥션

(Datasource 대신)은 리스팅 8에서와 같이 명시적으로 구성되어야 한다.

코드 리스팅 8: 독립형 JPA 단위 테스트를 위한 persistence.xml

<persistence>

<persistence-unit name=”test” transaction-type=”RESOURCE_

LOCAL”>

<provider>org.eclipse.persistence.jpa.PersistenceProvider</

provider>

<class>com.abien.messageme.business.messaging.entity.

Message</class>

<exclude-unlisted-classes>true</exclude-unlisted-classes>

<properties>

< p r o p e r t y n a m e = ” j a v a x . p e r s i s t e n c e . j d b c . u r l ”

value=”jdbc:derby:

./sample;create=true”/>

<property name=”javax.persistence.jdbc.password”

value=”app”/>

<property name=”javax.persistence.jdbc.driver” value=”org.

apache.derby

.jdbc.EmbeddedDriver”/>

Technology & Developer 설계 차원의 단순성 Spring 2011 66 67 Spring 2011 설계 차원의 단순성 Technology & Developer

Page 3: JavaEE6 - 설계 차원의 단순성

<property name=”javax.persistence.jdbc.user” value=”app”/>

<property name=”eclipselink.ddl-generation” value=”drop-

and-create-tables”/>

</properties>

</persistence-unit>

</Persistence>

컨트롤 레이어를 개발할 때, 그 컨텐츠가 엔터티 및 바운더리 레이어 리

팩토링(Refactoring)의 산물이 되어야 한다는 점을 유념해야한다. 쿼리

(Queries), 알고리즘(Algorithms) 또는 검증 등과 같이 바운더리 레이어

의 재사용 가능하고 응집력이 없는(Noncohesive)는 컨트롤 레이어의

CDI managed bean으로 추출되어야 한다.

ECB 패턴의 사용

ECB 패턴의 주요 목적은 비즈니스 및 프레젠테이션 로직 간의 명확한 구

분을 제공한다는 것이다. 정의에 따라 바운더리는 프레젠테이션 로직에

서 독립되어야 한다. 실제 아키텍처에서 많은 절충이 이루어지고 있지만,

비즈니스와 UI 기술 간의 명확한 구분이 이루어져야 한다. 실제로, UI 로

직은 비즈니스 로직보다 더욱 자주 변경되는 경향이 있다. 웹 클라이언트

(JSF 2 등), 리치 클라이언트(Swing 또는 Eclipse RCP 등) 그리고 REST

등에 의해 동시에 액세스될 수 있는 비즈니스 로직을 생성하는 것이 일반

적이다.

JSF 2의 경우, CDI는 컨트롤러(Controller) 또는 프레젠터(Presenter)를

구현하기 위한 가장 쉬운 옵션이다. CDI managed bean은 EL을 통해 JSF

2에 직접 바운딩될 수 있으며 바운더리(EJB 3.1)는 프레젠터로 직접 주입

될 수 있다. 프레젠터(또는 컨트롤러)는 @Stereotype 어노테이션으로 직

접 포착될 수 있다. 이는 매크로처럼 실행되며 그 안에 CDI 어노테이션을

배치하고 이 어노테이션으로 확장할 수 있다. 스테레오타입(Stereotype)

은 @Stereotype으로 표시되는 표준 Java 어노테이션이다.

@Named

@RequestScoped

@Stereotype

@Retention(RUNTIME)

@Target(TYPE)

public @interface Presenter {}

커스텀 스테레오타입(custom stereotype)은 매크로와 마찬가지로 @

Messaging boundary;

@Inject

IndexView indexView;

public void save(){

boundary.store(indexView

.getMessage());

}

}

바운더리와 뷰가 IndexPresenter에 주입되기 때문에 쉽게 mocking 할

수 있다. 단위 테스트 환경에서 두 필드는 mock을 이용해 설정되지만, 실

제 운영 환경에서는 컨테이너가 주입을 실행하고 실제 종속성을 설정하게

된다. 단위 테스트와 IndexPresenter가 동일한 패키지 내에 있기 때문에

기본 visible 필드는 직접 설정할 수 있다. public setter를 포함한 private

필드가 사용될 수 있지만, 대개의 경우 packagewide 필드로 충분하며

코드 사이즈를 줄일 수 있다.

리스팅 9는 IndexView는 물론, 바운더리 Messaging 클래스를

mocking화 함으로써 프레젠테이션 로직을 테스트하는 방법을 보여준다.

IndexPresenter.save() 메소드를 호출하는 이 테스트는 메소드 스토어

를 단 한 번 호출하고, IndexView에 의해 Message-Instance가 반환되

면 성공적이다. 호출을 검증한다는 것은 mock를 Mockito.verify() 메소

드로 보낸다는 것을 의미한다. IndexView는 JSF 렌더링과 상호 작용하

지 않고도 반환 값을 가공하도록 모의화에서 제외된다.

코드 리스팅 9: IndexPresenter테스트—모의화에서 제외된 뷰 및 바운

더리 이용

package com.abien.messageme.presentation;

//...other imports

import org.junit.Before;

import org.junit.Test;

import static org.mockito.Mockito.*;

public class IndexPresenterTest {

private IndexPresenter cut;

@Before

public void initialize(){

this.cut = new IndexPresenter();

}

Named 및 @RequestScoped 대신 적용될 수 있다. 그러면, 프레젠터 패

턴을 식별하는 모든 CDI 어노테이션을 대체할 수 있다.

@Presenter

public class Index {

//

}

프레젠터의 목적은 프레젠테이션 로직을 구현하는 것이다. 프레젠터의 구

조는 뷰와 긴밀히 결합되어 있으며 이 뷰 내 JSF 컴포넌트의 상태 내에서

프레젠터 내부의 속성으로 매핑될 수 있다. 속성은 값(값 바인딩으로)이나

컴포넌트 인스턴스 그 자체(컴포넌트 바인딩으로) 중 하나가 될 수 있다.

때때로 뷰와 프레젠터 간에 1대1 관계가 있는 경우도 있다. 이 프레젠터는

뷰의 데이터는 물론, 모든 프렌젠테이션 로직을 포함하고 있다. 바운더리

를 프레젠터에 주입하기 위해서는 @Inject 어노테이션을 사용해야 한다.

프레젠테이션 로직의 수가 프레젠터 내부에서 증가하고 있기 때문에 코

드를 유지하고 테스트하는 것이 더욱 어려워질 수 있다. CDI를 통해 단

일 프레젠터를 매우 손쉽게 분리된 데이터 및 프레젠테이션 로직 파트

로 분산시킬 수 있다. 예를 들어, 아래 코드는 save 메소드를 새로 만든

IndexPresenter 빈으로 옮겨 앞에 나온 예제에서 backing bean을 리

팩토링하는 방법을 보여주고 있다. 프레젠터 어노테이션은 중복되고 @

View으로 이름이 변경되며, 이 빈은 IndexView로 이름이 변경된다.

@View

public class IndexView {

private Message message = new Message();

public Message getMessage() {

return message;

}

}

IndexPresenter 빈은 이전 @Presenter 어노테이션을 가져온다. 아래

코드에서 볼 수 있듯이, 이 사례에서 IndexPresenter 빈의 유일한 목적

은 프레젠테이션 로직을 구현하는 것이다.

@Presenter

public class IndexPresenter {

@Inject

@Test

public void save() {

this.cut.boundary = mock(Messaging.class);

this.cut.indexView = mock(IndexView.class);

Message expected = new Message(“duke”);

w h e n ( t h i s . c u t . i n d e x V i e w . g e t M e s s a g e ( ) ) .

thenReturn(expected);

cut.save();

verify(this.cut.boundary,times(1)).store(expected);

}

}

메시징 바운더리는 다른 이유로 즉, 예상 메소드가 실제로 호출되었는지

를 검증하기 위해 모의화에서 제외된다.

public void save(){

boundary.store(indexView

.getMessage());

}

JSF 2 프레젠테이션의 설계는 리치 Swing 애플리케이션의 설계

와 유사하다. Model-View-Controller와 같은 공통의 패턴과 그 개

선—Supervising Controller 및 Passive View—은 JSF 2에도 적용될

수 있다. JSF와 리치 클라이언트 기술 간의 가장 중요한 차이점은 뷰가

렌더링되는 방법이다. Swing에서 개발자들은 Java로 뷰를 구현하지만,

JSF 2에서 개발자들은 XHTML 마크업을 사용한다. JSF 2에서 컨포넌트

의 값은 해당 클래스에 직접 바인딩될 수 있지만, Swing에서는 대개 뷰 자

체 내에 또는 모델에 저장된다.

C R U D와 같은 데이터 중심의 유스 케이스를 구현하려는 경우,

Supervising Controller가 Passive View보다 나은 옵션이다.

Supervising Controller 패턴에서 단일 패키팅 빈(IndexView)은 프레

젠테이션 로직과 뷰 상태 모두를 관리하는 책임을 맡고 있다. 더욱 복잡한

유스 케이스에서는 Passive View 변수가 보다 적합할 것이다. Passive

View 패턴에서는 backing bean이 뷰 및 프레젠테이션 로직으로 분산되

며 프레젠테이션 로직은 IndexView에서 IndexPresenter로 추출된다.

CDI는 프레젠테이션 레이어의 구현에 가장 적합하다. 기본 내장된 공통

관심 사항(Cross-cutting concerns, 여기에는 트랜잭션, 동시성, 비동기

식 실행 모니터링 및 스로틀링 등이 해당 됨) 때문에 비즈니스 로직의 바운

더리가 EJB로서 실체화된다. 비즈니스 컴포넌트는 EJB 또는 CDI로 실체

Technology & Developer 설계 차원의 단순성 Spring 2011 68 69 Spring 2011 설계 차원의 단순성 Technology & Developer

Page 4: JavaEE6 - 설계 차원의 단순성

71 Spring 2011 시뮬레이션을 통한 성능 증명 Technology & Developer

화될 수 있다. 일반적으로 CDI에서 시작하고, 시간이 지난 후, 특수한 케

이스의 managed bean을 EJB로 대체할 수 있다. CDI-EJB-CDI (CEC)

패턴은 Java EE 6을 위한 가장 단순하고 가장 실용적인 옵션이다.

인터페이스를 유용하게 만드는 방법

EJB 3.0 (Java EE 5에서)는 bean 클래스를 위한 별도의 인터페이스

를 요구했다. 네이밍 충돌을 방지하기 위해 개발자들은 종종 XyzLocal/

XyzRemote 및 XyzBean와 같이 체계적으로 규정된 명명 규칙을 사용해

야 했다. Java EE 6에서 EJB 및CDI를 위한 인터페이스는 이제 옵션이 되

었다. Public EJB 또는 CDI 메소드는 이제 그 어떤 기능의 손실도 없이

“no interface” 뷰를 보여줄 수 있다.

새로운 기능은 다시한번 인터페이스를 중요하게 만들었다. 이전 릴리스에

서 강제적이면서도 막연하게 인터페이스를 사용했던 것과는 달리, Java

EE 6 의 인터페이스는 Strategy 패턴의 구현, Public API의 구현 또는 엄

격한 모듈 분리(코드를 보다 분명하게 나타낼 수 있도록 함)를 위해 사용

될 수 있다. 인터페이스는 시스템의 “Protected variations”를 나타내고

클래스 간의 직접적인 종속성은 변경될 가능성이 낮은 코드를 위해 사용

될 수 있다.

인터페이스 없이 개발을 시작해서 필요에 따라서 이를 적용할 수 있다. 이

와 같은 접근 방식은 Java EE 5에서와 근본적으로 차이가 있다. 2003년

부터 나온 Java 2 Platform, Enterprise Edition (J2EE)에 비해 Java EE

6 코드는 여러 레이어, 간접 지정(Indirections) 및 추상화 등이 제거됨에

따라 훨씬 단순하다. J2EE와 달리, Java EE 6는 플랫폼에 대한 종속성 없

이 주석이 붙은 클래스로 구성되어 있다. 이와 같은 접근 방식은 인프라에

서 비즈니스 로직을 분리해야 하는 필요성을 없애고 대부분의 J2EE 패턴

과 모범 사례를 불필요하게 만든다. Java EE 6에서는 프레젠테이션 및 비

즈니스 로직으로 단순한 사례를 해결할 수 있다. EntityManager는 이미

충분히 훌륭한 주요 영속성의 추상화 기능을 제공하기 때문에 추가 간접

지정 기능은 전혀 필요하지 않다.

쉽게 유지 관리할 수 있는 Java EE 6 애플리케이션은 YAGNI (You Ain’t

Gonna Need It), DRY (Don’t Repeat Yourself), 그리고KISS (Keep It

Simple, Stupid) 원칙에 따라 작성된다. 설계 패턴과 모범 사례는 하향식

(Top-down)이 아니라 상향식(Bottom-up)으로 도입된다. 이와 같은 패

턴은 언제나 플랫폼의 한계가 아니라, 기능 및 비 기능 요구 사항에 의해

주도된다. 이러한 접근 방식은 Java EE 6과 이전 J2EE 릴리스 간의 가장

큰 차이점을 나타낸다. J2EE에서는 J2EE 플랫폼 종속성에 따라 많은 설

계 의사 결정이 사전에 이루어졌다.

반대로, Java EE 6 개발 프로세스는 기능에 초점을 맞추고 있다.

1. 비즈니스 문제를 직접 해결하는 단순한 코드 작성

2. 단위 테스트로 비즈니스 로직 검증

3. 종속성 단절 및 리팩토링으로 설계 향상

4. 애플리케이션에 대한 스트레스 테스트

5. 다시 1로 되돌아가기

설계 및 아키텍처는 일반적인 아키텍처 차원의 모범 사례가 아니라 구체

적인 요구 사항에 따라 이루어진다. 지속적으로(적어도 1주일에 한번) 애

플리케이션에 대한 스트레스 테스트를 수행함으로써, 확실한 사실(Hard

fact)을 이용하여 단순한 설계에 대한 타당성을 보다 손쉽게 입증하고 스

트레스가 가해졌을 때 시스템의 작동에 대한 정보를 확보할 수 있다.

SQL Performance Analyzer에서 Oracle Exadata 시뮬레이션 기능을

이용한 Oracle Exadata환경에서 실행되는 애플리케이션의 성능 예측

데이터베이스 시장의 ‘혁신적 파괴자’로 최근 등장한 Oracle Exadata

는 그 유형에 관계없이 애플리케이션 성능을 향상시키고 있다. 하지만,

Oracle Exadata로의 마이그레이션을 고려하고 있는 사람들이 가장 궁

금해 하는 것은 아마도 ‘기존 데이터베이스에서 실행 중인 애플리케이

션들이 Oracle Exadata에서 적절하게 실행되느냐’하는 것이다. 실제

로 Oracle Exadata로 마이그레이션을 하기 전에 그 해답을 확인할 수

있는 방법은 없을까? Oracle Database 11g Release 2에서는 Oracle

Exadata 어플라이언스에 실제로 투자하기 전에 Oracle Exadata에서

데이터베이스 작업을 시뮬레이션 및 측정할 수 있도록 지원하는 새로운

기능이 추가되었다. 이 글에서는 이 시뮬레이션 기능을 사용해 Oracle

Exadata에서 실행 중인 애플리케이션의 성능을 예측할 수 있는 방법에

대해 알아보겠다.

시뮬레이션을 위한 토대

Oracle Database 11g Release 1은 Oracle Real Application Testing

스위트의 구성 요소인 SQL Performance Analyzer를 새롭게 도입

했다(Oracle Magazine 2008년 3월/4월호 “Performing Through

Changes” 참조). 이 툴을 사용하면 모든 데이터베이스에서 SQL명령문

을 포착하고, 이를 새로운 환경에서 재현(replay)함으로써 잠재적 문제를

규명하고 새로운 대상 환경에서의 동작 상황을 예측할 수 있다.

대상 환경은 인덱스, materialized view 등이 더 많거나 적을 수 있고, 기

반구조가 다르거나, 다른 세션 매개변수 환경에서 운용되는 등 현재 운영

중인 환경과 구조적으로 다를 수 있다. Oracle Database 11g Release

2에서는 Oracle Exadata의 기능을 시뮬레이션할 수 있도록 SQL

Performance Analyzer의 범위가 확장되었다.

강력한 성능의 원천

시뮬레이션을 통한 성능 증명 :� 저자 - Arup Nanda

감수자 - 김상엽

Oracle Exadata가 이렇게 뛰어난 성능을 발휘할 수 있는 비결 중 하나는

바로 Oracle Exadata 스토리지가 위치한 스토리지 셀 내 인텔리전스로

서, 이는 성능에 가장 큰 영향을 미치고 있다. 스토리지 셀은 저장된 데이

터의 패턴을 알고 있기 때문에 모든 데이터가 아니라 연관성 있는 데이터

만 지능적으로 반환할 수 있다. 아래 간단한 쿼리를 통해 이를 살펴볼 수

있다.

select sum(order_qty)

from sales

where cust_id = 1000

기존 Oracle Database에서는 이미 메모리에 데이터 올라와 있는 경우가

아니라면 SALES 테이블부터 모든 블록을 버퍼 캐시(시스템 글로벌 영역

에 위치)로 가져오도록 서버 프로세스가 명령어를 실행한다. 그 다음, 세

션은 CUST_ID = 1000인 행을 찾기 위해 누적된 데이터를 검사한다. 값

이 일치하는 행들이 서버 프로세스의 프로그램 글로벌 영역으로 복사되

고 또 다른 열인 ORDER_QTY의 합계가 계산된 후, 마지막으로 결과가 사

용자에게 반환된다. 테이블은 10억 개까지 행을 가질 수 있고 CUST_ID =

1000인 행 수는 100개에 불과한 경우에도 일치하는 행을 찾으려면 데이터

베이스가 10억 개의 행을 모두 가져와서 검색해야 한다. I/O 서브시스템은

여전히 테이블의 모든 블록을 서버 프로세스로 반환해야 한다. 이 경우, 스

토리지는 데이터 구조에 대한 상황을 알지 못하기 때문에 관련 있는 데이

터와 나머지 데이터를 구별할 수 없다.

Oracle Real Application Clusters (Oracle RAC) 시스템에서도 또 다

른 문제가 있다. 병렬 쿼리 슬레이브가 여러 인스턴스 상에 분리되어 있

을 수 있다. 이들은 수집한 데이터를 대조를 위해 다른 인스턴스의 query

coordinator로 인터커넥트를 통해 전송하기 때문에 인터커넥트 하드웨

어가 이와 같은 트래픽으로 포화 상태가 된다. 뿐만 아니라, 인터커넥트를

통해 블록을 전송하는 프로세스는 CPU를 사용하는 데다 래치(Latch)를

필요로 하기 때문에 더 많은 CPU 사이클이 요구된다. 따라서, 스토리지

시스템으로부터의 블록에 대한 요구가 클수록 CPU 및 I/O와 인터커넥트

Technology & Developer 설계 차원의 단순성 Spring 2011 70

저자 : Adam Bien (blog.adam-bien.com)은 Java Champion으로서 컨설턴트, 강사, 소프트웨어 아키

텍트 겸 개발자로 활동하고 있으며 Real World Java EE Patterns: Rethinking Best Practices (lulu.

com, 2009). 등과 같은 Java 전문 서적을 집필한 저자이기도 하다. 그는 Oracle Magazine의 2010년 올

해의 Java 개발자(Java Developer of the Year)로 선정되었다.