IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  WebSphere | 오픈 소스  >

WebSphere Application Server와 함께 스프링과 OpenJPA 사용하기

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

샘플 코드

영어원문

영어원문


제안 및 의견
피드백

난이도 : 초급

Marko Asplund, 선임 컨설턴트, Ixonos oyj

원문 게재일 : 2008 년 10 월 29 일
번역 게재일 : 2008 년 12 월 23 일

본 글은 J2EE 프로젝트에서 스프링 프레임워크와 아파치 OpenJPA를 활용해 생산성과 애플리케이션 개발 경험을 향상시키는 방법을 보여줍니다. 이 글의 샘플 애플리케이션은 비즈니스 티어, 그 중에서도 서비스와 데이터 접근 레이어에 초점을 맞춰 각기 다른 웹 애플리케이션 아키텍처 레이어의 몇 가지 시나리오에 스프링을 사용하는 것입니다.

소개

스프링은 J2EE 개발을 단순하게 만든 자바(Java™) 프레임워크다. 여기에는 J2EE 애플리케이션의 모든 레이어용 설비가 있다. 또한 특정 프로그래밍 모델만을 강요하지 않으므로 런타임 환경에 국한되지 않는다. 즉, 자바 SE 환경 외의 다른 애플리케이션 서버에서도 사용할 수 있다. 특히 최근 스프링의 인기가 높아진 비결은 디자인 원칙 때문이 아닐까 한다. 어떤 스프링 지지자들은 스프링 프레임워크를 J2EE의 대안으로도 본다. 나는 J2EE를 사용한다고 스프링을 사용하면 안 되는 것도 아니고 그 반대도 아니며 이 기술들은 서로 보완이 된다고 생각한다.

OpenJPA는 JPA(Java Persistence API) 구현으로 그 뿌리는 SolarMetric Kodo JDO(Java Data Objects) 구현으로 돌아간다. Kodo는 BEA에 합병되면서 JPA를 구현하도록 확장했고 오픈 소스 코드 기반의 아파치 OpenJPA가 됐다. 현재 OpenJPA는 실용적인 자바용 객체 관계형 매핑 도구로 BEA와 IBM이 프로젝트에 기여 중이다.




위로


샘플 애플리케이션

알아야 할 점

WebSphere Application Server V6.1과 V7은 EJB3을 지원한다. 이는 JPA를 근본적으로 지원하고 스프링과 비슷한 많은 방법으로 개발을 단순화한다. 관련 자료를 보고 아래 참고자료에서 더 자세한 정보를 찾아보자.

본 글에서는 Events라는 기본 웹 애플리케이션을 사용해 WebSphere Application Server에서 작동하는 애플리케이션을 개발하는 데 스프링과 OpenJPA를 사용하는 다양한 기술을 보여준다. 이를 위해 간단한 애플리케이션을 설계하여 이 기술들이 어떻게 함께 사용되는지 보여주는 데 초점을 맞춘다. 샘플은 이벤트 추가, 이벤트 나열, 이벤트 편집(add event, list events, edit event)이라는 세 가지 간단한 유스 케이스(use cases)를 제공한다. 사용자가 입력하는 정보는 관계형 데이터에 남아 있다. 사용자는 시스템에 저장된 이벤트 리스트를 볼 수 있다(그림 1). 각 이벤트에서 이벤트 리스트는 내부 식별자와 이벤트 제목을 보여준다.


그림 1. 행사 나열하기
행사 나열 모양

사용자는 리스팅 뷰의 Add 버튼을 클릭해 행사를 추가할 수 있다. 행사를 추가할 때 사용자는 제목, 카테고리, 시작 시간과 기간 필드를 입력해야 한다. 필수로 입력해야 할 필드는 별표(*)로 표시된다(그림 2). 이벤트를 추가할 때 Id 필드는 휴지 상태다.

사용자는 또한 리스트 뷰에서 관련 Edit 링크를 사용해 이벤트 날짜를 수정할 수 있다.


그림 2. 행사 추가하기
행사 추가 모양

아키텍처 개요

Events 애플리케이션은 자바 SE 5와 J2EE 1.4를 사용하고 WebSphere Application Server 6.1에서 작동한다. 또한 JSF(JavaServer Faces) 1.1 기술을 사용해 사용자 인터페이스를 구현한다. 애플리케이션 아키텍처 전반에서 스프링 프레임워크를 활용하고 데이터 접근 레이어에서 JPA를 사용한다.

그림 3은 애플리케이션의 단순화된 구조적 뷰를 보여준다. JSF 페이지는 행사 정보를 로딩하고 저장하는 것 등의 성능 활동에 JSF로 관리되는 빈(bean)을 사용한다. 재사용성을 향상시키는 데 두 가지 유형의 관리된 빈이 있다. 하나는 활동(EventBacking)을 수행하는 빈이고 다른 하나는 상태(EventSession)를 가지는 빈이다. 활동(또는 백킹(backing)) 빈은 요청 범위이고 상태를 가지는 빈은 세션 범위다. 이렇게 분리하면 각기 다른 뷰에서 두 빈 유형 모두를 더 수월하게 재사용할 수 있다. 특히 애플리케이션에 뷰 수가 많을 때 더 그렇다. 백킹 빈은 현재 사용자 세션 상태를 처리할 수 있다. JSF 관리의 빈 설비를 통해 상태가 백킹 빈에 주입되기 때문이다.


그림 3. 아키텍처 다이어그램
아키텍쳐 흐름의 그래픽

백킹 빈은 행사 추가 요청 프로세스를 EventServiceEJB Stateless Session Bean에, 행사 나열하기와 저장하기를 EventService 구현에 위임한다. 일반적으로 데이터베이스 데이터에 접근할 때 웹이나 EJB 애플리케이션 티어 중 하나에서 접근하지 둘 다에서 접근하지 않는다. 샘플 애플리케이션은 두 티어 모두에서 서비스 레이어를 통해 데이터베이스에 접근해 둘 모두에서 스프링을 사용하는 방법을 보여준다.

더 나아가 EventServiceEJBEventService 인터페이스 구현 클래스에 프로세싱을 위임한다. 그러고 나서 서비스 구현 클래스는 DAO(Data Access Object) 구현 클래스를 사용해 퍼시스턴트 데이터 저장소와 통신한다. 서비스 레이어는 특정 행사를 찾고, 행사를 만들고 업데이트하고 제거하고 모든 행사를 나열하는 메서드를 갖는다. DAO는 JPA EntityManager(그림 4를 보자)를 사용해 데이터베이스 데이터에 접근한다.


그림 4. 서비스 레이어 다이어그램
서비스 레이어의 그래픽

아키텍처에는 실생활 애플리케이션을 모방하는 아키텍처를 만드는 것을 주 목적으로 하는 서비스 레이어를 포함한 몇 가지 레이어가 있다. EventService 서비스 레이어가 성취하는 구체적 기능은 트랜잭션 관리용 플러그인 포인트 역할을 한다(이후에 보여주겠다).

애플리케이션의 도메인 모델(그림 5)에는 JPA 엔티티로 구현한 Event라는 단일 자바 클래스가 있다. 이 엔티티를 관련된 행을 포함하는 단일 데이터베이스 테이블에 매핑해 보겠다.


그림 5. 도메인 모델
도메인 모델의 그래픽

애플리케이션은 네 가지 프로젝트로 구성된다.

  • events-ear: EAR 패키징, 공유된 라이브러리 등
  • events-ejb: 비즈니스 로직 티어, EJB 세션 빈
  • events-service: 서비스 레이어와 데이터 접근
  • events-war: 웹 티어

개발

IDE를 사용해 샘플 애플리케이션을 작업하려면 사전에 필요한 다음과 같은 소프트웨어를 설치해야 한다.

  • 자바 EE용 이클립스 3.4
  • IBM WebSphere Application Server v6.1(v6.1.0.9나 6.1 이후 버전. 샘플 애플리케이션은 v6.1.0.17에서 테스트됐다)
  • 자바 SE JDK 1.5(JDK 번들과 WebSphere Application Server를 사용할 수 있다)
  • IBM DB2(DB2 UDB 8.2나 아파치 더비 v10.4.2.0)

샘플 애플리케이션은 스프링 프레임워크 v2.5.5와 아파치 OpenJPA v1.2.0(사용된 다른 API나 버전 목록은 events-ear/docs/libraries.txt 파일을 보자)을 사용한다.

애플리케이션 프로젝트를 다음과 같이 설정하자.

  1. events.zip 패키지를 다운로드하고 압축을 푼다.
  2. 소스 트리를 이클립스에 임포트한다. File 메뉴의 Import를 선택하고 General / Existing Projects into Workspace를 선택한다. 압축 푼 소스 트리 루트 디렉터리를 임포트 루트로 선택한다. Import 대화상자는 그림 6처럼 보여야 한다.

    그림 6. 프로젝트 임포트하기
    이클립스 임포트 모양

  3. WAS 6.1 J2EE라는 사용자 라이브러리를 만들자. Window - Preferences를 선택하고 난 후 Java / Build Path / User Libraries로 이동한 다음 New를 클릭해 새 라이브러리를 만들자. 이 때 이름을 WAS 6.1 J2EE로 하는 것이 중요하다. 그래야 라이브러리가 자동으로 events-ejb와 events-war 프로젝트 빌드 경로에 추가된다(그림 7을 보자). 라이브러리를 만든 후 WAS 6.1 설치에서 j2ee.jar 파일을 라이브러리에 추가하자. 파일은 ${app_server_root}/lib/j2ee.jar에서 찾을 수 있을 것이다(app_server_root가 Application Server 6.1 설치 루트 디렉터리로 참조되는 곳).

    그림 7. 사용자 라이브러리 만들기
    이클립스 사용자 라이브러리 모양

  4. 필요한 클래스 라이브러리를 받고 이를 events-ear/docs/libraries.txt에서 설명한 것처럼 프로젝트 트리의 정확한 장소에 놓는다.
  5. events-ear 디렉터리의 build.properties 파일을 편집한다. was-profile.root 변수 값을 Application Server 6.1 설치 경로에 반영해야 한다.
  6. 프로젝트 EAR 파일을 만든다. events-ear 하의 build.xml 빌드 파일을 열자. 이클립스 ouline 뷰의 "dist" 타겟을 오른쪽 클릭하고 Run As / Ant Build를 선택한다. 완성되면 EAR 파일을 소스 트리 루트 하의 dist 디렉터리에서 찾을 수 있을 것이다.

배치

애플리케이션 EAR 패키지를 만들 때 애플리케이션 서버에 events.ear를 배치하기 위해 아래의 프로시저를 사용하기 바란다. 프로젝트 구조의 루트 하에 dist 디렉터리에서 EAR 패키지를 찾을 수 있을 것이다.

  1. 애플리케이션용 데이터베이스 스키마를 만들거나 기존 스키마를 선택하자.
  2. events.ddl DDL문을 실행해 데이터베이스 테이블을 만들자(events-service/setup에).
  3. WAS Console을 열고 이미 만들어 놓은 데이터베이스 스키마에 연결되는 XA 데이터 소스를 설정하자. 그림 8처럼 데이터 소스용으로 JNDI 이름 jdbc/eventDS를 사용하자.


    그림 8. 빈용 JNDI 이름 제공하기
    애플리케이션 서버 콘솔 - JNDI 이름 모양

  4. 애플리케이션을 배치하자. Application Server 콘솔에서 Applications / Enterprise Applications 순으로 이동한 후 Install을 클릭한다. 배치 마법사가 시작된다. 새 애플리케이션의 경로를 넣으라는 문구가 나오면 events.ear 파일의 경로를 선택한다.
  5. 그림 9처럼 ejb/EventServiceEJB 리소스 레퍼런스를 ejb/EventServiceEJB에 매핑한다.

    그림 9. EJB 레퍼런스를 빈에 매핑하기
    애플리케이션 서버 콘솔 - Map EJB 레퍼런스 모양

  6. jdbc/eventDS 리소스 레퍼런스를 jdbc/eventDS JNDI 이름에 매핑한다(그림 10).

    그림 10. 리소스 레퍼런스를 리소스에 매핑하기
    애플리케이션 서버 콘솔 - Map 리소스 모양

  7. 마지막으로 배치 마법사를 마칠 때 Manage Applications을 클릭하고 events-ear / Manage Modules / events-war를 선택한다. 클래스 로더 순서를 Classes loaded with application class loader first로 설정하고 OKSave를 클릭한다.

    그림 11. events-war 모듈 관리하기
    애플리케이션 서버 콘솔 - Manage events 모양

  8. Enterprise Applications 목록에서 애플리케이션을 시작한다. 애플리케이션이 시작되면 녹색 화살표가 Application Status 행 아래에 보여야 한다.
  9. 브라우저에
    http://localhost:9080/events-war/faces/jsp/eventsList.jspx를 입력해 애플리케이션에 접속한다. URL은 Application Server URL을 반영해야 한다.



위로


스프링 프레임워크와 OpenJPA 사용하기

지금까지 유스 케이스, 개발, 배치 관점에서 샘플 애플리케이션을 다뤘다. 이제 스프링과 OpenJPA를 부트스트래핑(bootstrapping)하고 사용하는 방법을 알아보자. 다음 절에서는 자바 엔터프라이즈 개발자의 삶을 편하게 해 주는 느슨한 연결(loose coupling), 트랜잭션 관리, 예외 처리, 데이터 접근, 분산 지원을 포함한 몇 가지 스프링 메커니즘을 사용하는 방법을 소개하겠다.

컨테이너 인스턴스화

스프링 프레임워크의 기본 원칙 중 하나는 개발자가 서비스 객체(스프링 언어의 빈)와 객체 간 상호의존성을 선언해 프레임워크 내부의 경량 컨테이너로 관리하는 것이다. 컨테이너는 선언된 빈과 이것들의 의존성 생명주기를 관리해야 한다. 컨테이너가 인스턴스화되면 스프링은 선언된 협력 객체를 묶는다. 의존적 객체가 그 통합자를 검색하는 것과 반대로 의존적 객체가 이것들의 통합자에 접근하는지 프레임워크는 확인해야 하므로 스프링을 통제의 전도(IoC, Inversion of Control) 컨테이너라고도 부른다. XML 구성 파일처럼 다른 메커니즘을 사용해 빈을 선언할 수도 있다. 또한 프로그램 기반이나 주석 기반의 빈 선언을 사용할 수도 있다.

애플리케이션 티어에 따라 약간 다르게 컨테이너를 인스턴스화할 수도 있다. 웹 티어에서는 /WEB-INF/web.xml 파일에 있는 Listing 1의 XML 조각을 간단히 넣어 컨테이너를 인스턴스화할 수 있다.


Listing 1. listener 클래스
<listener>
  <listener-class>
    org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>

이 클래스는 스프링 빈 선언을 포함한다고 예측되는 /WEB-INF/applicationContext.xml 파일을 기본으로 로드한다. 필요하면 이 기본 구성 파일 경로를 커스터마이즈할 수 있다. 웹 애플리케이션의 ServletContext는 컨테이너 인스턴스용 바인드 타겟으로 사용돼 몇 번이고 인스턴스화할 필요 없이 지속적으로 사용할 수 있다.

J2EE 1.4의 웹 티어 초기화 메커니즘에서 EJB 애플리케이션을 초기화하는 표준 방법이 없으므로 스프링 컨테이너를 약간 다르게 인스턴스화해야 한다. 스프링은 컨테이너를 만들고 로드하는 데 몇 가지 다른 구현 클래스를 가지고 있다. 컨테이너를 인스턴스화하는 데 비용이 많이 들어가므로 인스턴스화가 필요할 때마다 하는 것은 피해야 한다. EJB 명세에 컨테이너 인스턴스를 공유하는 적절한 설비가 없으므로 싱글턴 기반의 인스턴스화 전략을 사용하는 것이 좋다.

이 메서드를 사용하려면 대체로 다른 빈 구성 파일의 세트를 로드하는 beanRefContext.xml이라는 (기본으로) EJB에 한정된 스프링 부트스트랩 구성 파일을 만들어야 한다. 또한 EJB 구현 클래스의 setSessionContext를 무효화해야 한다. 컨테이너 인스턴스화는 웹 티어에서와는 다르게 EJB 티어에서는 침입적이지 않다. 가시적인 장애 하나는 스프링 API를 사용해 빈을 명확히 검색해야 한다는 것이다.

비슷한 접근으로 스프링의 추상 EJB 구현 지원 클래스를 EJB 구현의 기본 클래스로 사용하는 것이다. 이런 편리한 클래스들은 코더들이 EJB 컴포넌트 인터페이스 메서드를 구현하는 것을 더 편하게 해줄 뿐 아니라 스프링 컨테이너 인스턴스화도 돕는다. 하지만 여전히 beanRefContext.xml을 만들어야 하고 setSessionContext를 구현해야 한다. 이 방법의 단점은 자신의 EJB 기본 클래스를 사용할 수 없다는 것이다.

가끔 웹 티어에서조차 ServletContext가 없는 경우가 있다. 써드파티 애플리케이션이나 프레임워크를 확장할 때 발생할 수 있는데 스프링 빈을 코드에서 사용하고자 하지만 API가 확장된 클래스에 컨텍스트를 전달하지 않아 생기는 일이다. 이런 경우 스프링 컨테이너를 위의 EJB 티어에서 설명한 것과 같은 방식으로 인스턴스화할 수 있다.

의존성 주입

스프링에서는 컨테이너가 의존성 주입(DI, Dependency Injection)이라는 기술을 사용해 의존적 객체에 있는 협업 객체에 레퍼런스를 만들 수 있다. 의존성 주입은 협업 객체에 접근을 제공하는 표준 J2EE 메커니즘과는 다르다. J2EE에서는 이름 공간을 통해 협업 객체를 만들기 위한 메커니즘으로 JNDI ENC(Environment Naming Context)를 사용하고 이것들에게서 레퍼런스를 얻는다. JNDI ENC를 사용함으로써 의존적 객체는 레퍼런스를 일정한 협력자에 요청할 수 있다.

스프링 DI를 사용할 때 프로그래머는 의존적 객체에 협력자 레퍼런스를 만들고 구성자나 설정자 주입 변형을 사용해 컨테이너가 의존성을 해결하도록 요청한다. 구성자 주입(constructor injection)으로 컨테이너틑 구성자 요청에 협력자를 보내는 반면 설정자 주입으로 컨테이너는 의존적 객체를 만들고 난 후 변경자 메서드 호출을 사용해 레퍼런스를 전달한다. 두 경우 모두에서 의존성을 선언해야 하고(예로 스프링 구성 파일을 사용해) 그에 맞는 구성자나 변경자 메서드를 의존적 객체 클래스에 추가해야 한다.

Design Patterns: Elements of Reusable Object-Oriented Software라는 디자인 패턴에 관한 고전은 "구현이 아닌 인터페이스로의 프로그램"이라는 디자인 원칙을 지향한다. 인터페이스에 프로그램을 해도 구현 클래스는 어디선가 여전히 인스턴스화돼야 한다. 간단히 프로그램적으로 인스턴스화할 수 있지만 코드는 구체적 구현 클래스에 의지할 것이다. 다른 접근은 구현을 인스턴스화하기 위해 팩토리 클래스를 만드는 것이지만 코드에는 여전히 구현 클래스에 의존성이 있을 것이다. 의존성이 적은 숫자에 한정될 수 있더라도 소스 코드 수준의 의존성은 여전히 존재한다는 것에 주의하자.

Listing 2의 인터페이스 EventService 구현 클래스가 이 접근을 설명한다. 여기서 서비스 구현은 DAO 구현 클래스가 아닌 EventDAO 인터페이스에서 소스 수준의 의존성만을 가진다.


Listing 2. EventService 인터페이스 구현
public class EventServiceImpl implements EventService {
  private EventDAO eventDAO;

  public void setEventDAO(EventDAO eventDAO) {
    this.eventDAO = eventDAO;
  }
  // ??}

의존성은 다음과 같이 스프링 구성에서 선언된다.

<bean id="eventDAO" class="events.service.EventDAOJPA"/>

<bean id="eventService" class="events.service.EventServiceImpl">
  <property name="eventDAO" ref="eventDAO"/>
</bean>

스프링은 구성 파일에서 의존성을 선언하게 하고 난 후 의존적 객체에 협력자를 묶음으로써 느슨한 연결을 제공한다. 이를 통해 구현 클래스에서 호출자를 완전히 떼어내는 것이 가능해지고 코드가 더 유연해진다. 이제 구현 클래스를 바꾸는 것은 스프링 구성 파일을 간단히 수정하는 문제가 된다.

예외 처리

최근 몇 년 간 자바 API가 자바 예외 모델을 사용하는 방법에 대한 비판이 일었다. 프로그래머는 실생활에서 일어나기 힘든 잘못된 상태를 처리하도록 하면 안 되고 논리적으로 복구할 수 없는 실패에 대해 시스템이나 프로그래머가 책임을 질 필요가 없다고 많은 사람이 주장해왔다. 대신 이런 상태에서 확인되지 않은 예외를 사용해 이 상태들을 자유롭게 처리할 수 있어야 한다. 이런 교과서적인 생각에서는 일반적인 운영 시간에 나타날 거라 예상되는 애플리케이션이나 사용자 오류만이 확인된 예외를 사용해 보고돼야 한다. 이 예외 처리 전략은 스프링을 비롯한 이런 생각을 가진 많은 프레임워크와 API에서 폭발적인 반응을 불러 일으켜왔다.

서비스 레이어 지원

잘 설계되고 구현된 서비스 레이어를 가지면 애플리케이션의 확장성과 활동성에 긍정적 영향을 준다. 새 최종 사용자 기능을 추가하고 기존 것을 수정하는 것은 높은 수준의 재사용 가능한 서비스 레이어를 더 간단하게 만들어준다.

트랜잭션 분리(Transaction demarcation)는 구현이 제대로 되지 못했을 때 서비스 레이어의 재사용성에 부정적 영향을 줄 수 있다. 너무나 다양한 유스 케이스를 구현하는 데 서비스 레이어를 사용할 수 있으므로 이는 문제가 될 수 있다. 다른 컨텍스트에서도 서비스 레이어 호출자가 연산해야 하기 때문이다. 호출자는 트랜잭션 요구사항을 변경해 서비스 레이어가 호출자로 하여금 트랜잭션 처리에 영향을 줄 수 있도록 할 것이다.

애플리케이션의 트랜잭션 요구사항이 복잡하지 않을 때 프로그램적인 트랜잭션 분리는 성가시고 오류가 날 가능성이 더 높아질 수 있다. 선언적 트랜잭션 분리(declarative transaction demarcation)를 통해 소프트웨어의 트랜잭션 행위의 규칙을 선언할 수 있고 트랜잭션 매니저가 자동으로 이 규칙들을 수반할 수 있도록 할 수 있다. 스프링은 프로그램적인 트랜잭션 분리와 선언적 트랜잭션 분리 모두를 지원한다. 샘플 애플리케이션은 Listing 3의 선언을 사용해 서비스 레이어의 트랜잭션 속성을 정의한다.


Listing 3. 트랜잭션 속성
<tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
    <tx:method name="*" propagation="REQUIRED"/>
  </tx:attributes>
</tx:advice>

<aop:config>
<aop:pointcut id="serviceMethods"
       expression="execution(* events.service.EventService.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/>
</aop:config>

이 구성은 AOP(Aspect Oriented Programming)용 스프링 지원을 사용한다. Listing 3에서 트랜잭션 조언자 객체(transaction advisor object)라는 것을 정의하고 트랜잭션 매니저를 이 조언자와 결합했다. 트랜잭션 조언자가 모든 선언된 메서드에 REQUIRED 트랜잭션 속성을 적용하도록 명령했다. REQUIRED 트랜잭션 속성의 시맨틱은 J2EE의 그것과 같다. 즉, 메서드가 트랜잭션 내에서 항상 실행할 것을 의미한다. 호출자가 트랜잭션 컨텍스트에서 작동하면 메서드는 호출자의 컨텍스트에서 실행한다. 그렇지 않다면 새 트랜잭션 컨텍스트를 만든다.

그러고 나면 aop:config 부분이 메서드의 세트를, 즉 events.service.EventService 인터페이스의 모든 메서드를 트랜잭션 선언하도록 정의한다. 트랜잭션적으로 조언된 클래스는 특정 컴포넌트 인터페이스를 구현할 필요가 없다. 트랜잭션 속성이 POJO(Plain Old Java Object) 클래스를 위해 지정될 수 있다. 이를 구현하려고 스프링은 원래 서비스 객체를 트랜잭션 프록시로 싼다. 여기서 주의할 점은 서비스 객체의 로컬 호출이 트랜잭션 프록시를 통해 가지 않기 때문에 호출자의 트랜잭션 컨텍스트에서 늘 발생한다는 것이다.

스프링은 트랜잭션 매니저 인터페이스 구현을 사용해 런타임에서 실제 트랜잭션 분리를 수행한다. 서비스 레이어를 구성해 표적 환경의 능력에 따라 다른 트랜잭션 매니저를 사용할 수 있다. 예를 들어, 서비스 레이어가 J2EE 애플리케이션 서버에서 작동한다면 Listing 4처럼 스프링으로 하여금 애플리케이션 서버의 트랜잭션 매니저를 사용하라고 명령할 수 있다.


Listing 4. 트랜잭션 매니저 구성
<tx:jta-transaction-manager/>

이 구성으로 스프링이 자동으로 애플리케이션 서버의 트랜잭션 매니저를 사용할 수 있도록 한다. 자바 SE 환경에서는 Listing 5처럼 스프링을 구성해 JPA API의 트랜잭션 분리 설비를 사용할 수 있었다.


Listing 5. JPA 트랜잭션 매니저 선언
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="emFactory"/>
</bean>

이 기술을 통해 코드를 수정할 필요 없이 EJB와 웹 티어, 심지어는 자바 SE 환경에서 사용할 수 있는 서비스 레이어를 구현할 수 있다. 컨테이너 외부에서 서비스 레이어를 테스트하는 것 또한 매우 쉬우며 이를 통해 개발 주기를 줄일 수 있다.

서비스 레이어 재사용성에 부정적 영향을 끼칠 수 있는 또 다른 문제는 예외 처리 전략이다. 애플리케이션 전반에서 예외를 긴밀히 처리해야 한다. 대체로 시스템 오류를 처리할 필요는 없지만 필요에 따라 이런 프로세스를 밟을 수도 있다. 간혹 JDBC와 JPA 같은 데이터 접근 API가 예외적 상태에 관한 아주 일반적인 정보만을 제공할 수 있고 효과적으로 식별될 수 있는 특정한 이유를 거부하기도 한다. 서비스 레이어가 특정 엔터프라이즈 정보 시스템에 저장된 데이터에 접근하려고 데이터 엑세스 레이어를 사용할 때 서비스 레이어는 상층 레이어에 어떤 정보 시스템에 한정된 예외도 전파해서는 안 된다.

스프링은 서비스 레이어 예외와 DAO 레이어 예외에 기본으로 사용할 수 있는 밀집된 데이터 접근 예외 클래스 계층(그림 12)을 정의한다. 스프링의 데이터 접근 설비는 데이터 접근 예외를 이 예외 클래스 계층에 자동으로 옮긴다. 이 계층을 또한 필요에 따라 자신만의 더 특화된 예외로 확장할 수도 있다. 이전에 언급했듯이 이 계층의 예외는 확인되지 않았다(이 다이어그램의 더 큰 버전을 보자).


그림 12. 스프링 데이터 접근 예외 계층(스프링 레퍼런스 문서의 다이어그램)
스프링 레퍼런스 문서 다이어그램

DAO 지원

JPA의 주요 컨샙은 퍼시스턴스 컨텍스트다. 관계형 데이터베이스에 반하는 데이터 접근 운영을 실행할 수 있도록 하는 퍼시스턴스 컨텍스트와 상호 작용한다. 퍼시스턴스 컨텍스트는 관리된 객체 상태와 데이터베이스에 저장된 엔티티 상태를 동기화한다. EntityManager 인터페이스로 퍼시스턴스 컨텍스트에 접근할 수 있다.

애플리케이션 런타임 환경이 컨테이너로 관리되는 퍼시스턴스 컨텍스트를 지원하지 않을 때 컨텍스트의 생명주기는 애플리케이션에 의해 관리돼야 한다. 이는 약간 성가실 수 있으나 다행히 스프링이 지원한다. Listing 6의 행은 스프링 컨테이너와 통제하에 관리된 빈을 강화하는 빈 포스트 프로세서(post-processors) 세트를 구성한다.


Listing 6. 스프링 컨테이너 구성하기
<context:annotation-config/>

이 중에서도 스프링 빈에서 주석을 처리하는 프로세스는 JPA 퍼시스턴스 컨텍스트를 Listing 7의 DAO 구현 클래스 같은 자바 클래스에 주입할 수 있다.


Listing 7. JPA 퍼시스턴스 컨텍스트
@PersistenceContext
private EntityManager em;

이 주석은 스프링이 트랜잭션 퍼시스턴스 컨텍스트를 클래스 인스턴스에 주입할 수 있도록 한다. 스프링이 컨테이너로 관리되는 퍼시스턴스 컨텍스트와 POJO를 가지고 있는 상태를 모의 실험하므로 DAO 구현 레이어는 훨씬 깨끗해진다. 자바 EE 5에서는 POJO가 아닌 EJB 같은 관리된 객체에만 퍼시스턴스 컨텍스트를 주입할 수 있음에 주의하자.

또한 스프링이 데이터 구현 클래스용 데이터 접근 예외를 전달하는데 Listing 8의 한 행을 스프링 구성 파일에 추가만 하게 하면 된다.


Listing 8. 데이터 접근 예외 전달하기
<bean class="org.springframework.dao.annotation.
      PersistenceExceptionTranslationPostProcessor"/>

추가적으로 DAO 구현 클래스는 @Repository로 주석을 달아야 한다.

JSF 지원

JSF는 JSF EL식의 최상위 변수 해답을 커스터마이즈하기 위한 메커니즘을 가지고 있다. 스프링은 JSF식의 스프링으로 관리되는 빈을 참조할 수 있도록 하는 변수 해결자(resolver) 구현 클래스를 갖는다. 각각의 최상위 변수 이름을 위해 클래스는 먼저 스프링 컨테이너에 빈의 ID가 존재하는지 확인한다. 빈이 존재하면 클래스는 이 빈에 레퍼런스를 분석한다. 그렇게 하지 않는다면 JSF 기본 변수 해결자를 조사한다. 이 해결자를 사용하면 스프링 빈을 JSF로 관리되는 빈에 주입할 수 있거나 스프링 빈을 JSF 페이지의 EL식에 참조할 수 있다. Listing 9는 faces-config.xml 파일의 변수 해결자를 어떻게 구성하는지 보여준다.


Listing 9. 변수 해결자 구성하기
<variable-resolver>
	org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>

EJB 빈에 접근하기

EJB 세션 빈을 사용하면 호출자 측면에서는 매우 장황한 코드를 가질 수 있다. 원격의 상태없는 세션 빈으로 구현되는 서비스 메서드를 검색, 호출하는 전형적인 코드 조각은 Listing 10처럼 보일 수 있다.


Listing 10. EJB 세션 빈용의 장황한 코드
try {
  Context ctx = new InitialContext();
  Object homeObj = ctx.lookup("java:comp/env/ejb/EventServiceEJB");
  EventServiceEjbHome eventHome = (EventServiceEjbHome)
    PortableRemoteObject.narrow(homeObj, EventServiceEjbHome.class);
  EventServiceEjb eventService = eventHome.create();
  String msg = eventService.getGreeting("world");
} catch (NamingException e) {
  // handle exception
} catch (CreateException e) {
  // handle exception
} catch (RemoteException e) {
  // handle exception
}

룩업 코드와 예외 처리는 Listing 10을 장황하게 만드는 주 요소다. 이 문제들을 해결하는 가장 전형적인 방법은 서비스 사용자가 서비스 구현 클래스를 참조하도록 호출하는 분리된 클래스로 룩업 코드를 이동하는 ServiceLocator 패턴을 구현하는 것이다. ServiceLocator는 또한 확인된 예외(룩업이나 빈이 만들어지는 동안 버려진)를 확인되지 않은 예외로 전달할 수 있다. EJB를 사용할 때 여전히 RemoteException 예외를 처리해야 한다.

다시 말하지만 스프링은 이 문제에 적절한 해결책을 제시한다. EJB 빈을 스프링 구성의 스프링 빈으로 지정하고 난 후 스프링의 일반적인 의존성 주입 메서드를 사용해 어떤 스프링 빈에든 협력자로 주입할 수 있다.


Listing 11. 원격의 상태없는 세션 빈을 스프링 빈으로 선언하기
<jee:remote-slsb id="eventServiceEjb"
 jndi-name="java:comp/env/ejb/EventServiceEJB"
 business-interface="events.service.EventService"
 home-interface="events.ejb.EventServiceEjbHome"/>

표적 필드 유형이 EJB 비즈니스 인터페이스 유형을 지정한다면 호출자는 EJB를 호출하는 데 아무런 문제가 없다. 스프링은 NamingExceptionRemoteException 같은 예외를 잡고 자유롭게 처리할 수 있는 확인되지 않은 예외로 다시 이것들을 던질 수 있다. 스프링은 또한 실제 EJB 원격 인터페이스 조각 대신 프록시 객체에 레퍼런스를 주입해 비즈니스 메서드 호출 동안 버려진 예외를 처리할 수 있다. 이 방법에서 프록시는 EJB로 향하는 호출을 가로막고 적절히 예외를 전달할 수 있다. 원격 메서드 호출은 여전히 조심해야 할 call-by-value 시맨틱을 사용한다.




위로


결론

스프링은 전통적인 J2EE 프로그래밍이 가진 문제점들을 단순하게 함으로써 생산성을 높일 수 있다. 또한 기존 코드 기반이나 신설 애플리케이션에 공격적이지 않은 디자인으로 쉽게 소개될 수 있다. 어떤 설비로 배치하는지를 선택할 수도 있다. 적은 부분만이 요구된다면 전체를 사용하지 않아도 된다. 스프링은 WebSphere Application Server와 OpenJPA와도 잘 통합된다. 이 글에서는 몇 가지 스프링 기능을 어떻게 사용하는지 보여줌으로써 아래의 참고자료에서 시작해 프로젝트에 도움이 되는 다른 기능들도 찾아볼 수 있도록 돕는다.





위로


다운로드 하십시오

설명이름크기다운로드 방식
예제 웹 애플리케이션events.zip37KBHTTP
다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기


필자소개

author photo

Marko Asplund는 기업 정보 시스템 디자인과 구현, 대체로 자바 기술을 사용하는 구현을 전문으로 하는 선임 컨설턴트다. Marko Asplund는 썬 공인 엔터프라이즈 아키텍트, 썬 공인 비즈니스 컴포넌트, 개발자, 썬 공인 자바 프로그래머다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



 


 


 


이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us



IBM, Rational, and WebSphere are trademarks of IBM Corporation in the United States, other countries, or both. Apache is a trademark of The Apache Software Foundation. Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. 기타 회사, 제품, 및 서비스명은 다른 상표나 서비스 마크일 수 있습니다.

developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의