2장. 아키텍처

오픈소스 비즈니스 컨설팅
이동: 둘러보기, 검색

2.1 개요

다음은 (매우) 높은 수준의 Hibernate 아키텍처입니다.

Overview.gif

위의 다이어그램은 어플리케이션에 저장 서비스(와 저장 객체)를 제공하는 DB와 설정을 사용하는 Hibernate를 나타냅니다.

실행시 아키텍처에 대해 더 세부적인 그림을 보여줄 것입니다. 불행히도, Hibernate가 유연해서 몇가지 방법들을 지원합니다. 두가지 극단적인 것을 보여줄 것입니다. "가벼운(lite)" 아키텍처는 어플리케이션이 자신의 JDBC 연결을 제공하고 자신만의 트랜잭션을 관리해주게끔 합니다. 이러한 방법은 다음과 같이 Hibernate의 API의 최소한의 구성요소를 사용합니다.

Lite.gif

"전체(full cream)" 아키텍처는 어플리케이션을 내부의 JDBC/JTA API로부터 추상화사키며 Hibernate가 세부사항을 관리하게 해줍니다.

Full cream.gif

다음은 다이어그램의 객체에 대한 몇가지 정의입니다.

SessionFactory (org.hibernate.SessionFactory)

단일 DB에 대한 컴파일된 맵핑의 쓰레드 안전한(immutable) 캐쉬. 
Session과 ConnectionProvider의 클라이언트를 위한 factory. 
프로세스 차원 혹은 클러스터 차원에서 트랜잭션 간에 재사용될 수 있는 
데이터에 대한 선택적인 (2차 수준의) 캐시를 포함할 수 있음.

Session (org.hibernate.Session)

어플리케이션과 저장소 간의 연결을 대표하는 단일 쓰레드이며, 짧게 생존하는 객체.
JDBC 연결을 감싸고 있음. Transaction에 대한 factory.
객체 그래프를 항해하거나 객체를 식별자에 의해서 검색할 때 사용되는 
저장 객체에 대한 필수(1차 수준의) 캐시를 포함함.

저장 객체(Persistent objects)와 콜렉션

저장 상태와 비즈니스 기능을 포함하는 짧게 생존하고 단일 쓰레드의 객체.
보통의 JavaBean/POJO 이며, 특별한 것은 (정확하게 한개의) Session과 현재 관련되어 있음.
Session이 닫히자마자, detached 가 되며 어떠한 어플리케이션 레이어에서 사용하는데 제한이 없음.
(예를 들어, 화면과 데이터 전송 객체(data transfer object)처럼 직접적으로)

임시적이고(transient) detached된 객체와 콜랙션

현재 Session과 관련이 없는 저장 클래스들의 인스턴스들.
어플리케이션에 의해서 초기화될 수 있으며 아직은 저장 상태가 아니거나
닫혀진 Session에 의해서 초기화될 수도 있음.

Transaction (org.hibernate.Transaction)

(선택사항) 원자성의 단위 작업을 지정하기 위해 어플리케이션이 사용하는 단일 쓰레드이며 짧게 생존하는 객체.
어플리케이션을 내부의 JDBC, JTA 혹은 CORBA 트랜잭션으로부터 추사화시킴.
Session은 어떤 경우에 몇가지 Transaction들로 확대될 수 있음. 하지만,
트랜잭션 선언은 내부 API이건 Transaction이건 절대 선택사항이 아님!

ConnectionProvider (org.hibernate.connection.ConnectionProvider)

(선택사항) JDBC 연결(그리고 풀을)을 위한 factory. 어플리케이션을 내부의
Datasource 나 DriverManager로부터 추상화시킴. 어플리케이션에 노출되지 않으나, 
개발자가 확장/구현할 수 있음.

TransactionFactory (org.hibernate.TransactionFactory)

(선택사항) Transaction 인스턴스를 위한 factory. 어플리케이션 노출되지 않으나,
개발자가 확장/구현할 수 있음.

확장 인터페이스

Hibernate는 저장 계층의 행위를 변경하기 위해서 구현할 수 있는 많은 선택적인 
확장 인터페이스를 제공함. 자세한 내용은 API 문서를 참조.


"가벼운" 아키텍처에서 어플리케이션은 Transaction/TransactionFactory 이나 ConnectionProvider API를 JTA나 JDBC를 직접적으로 호출하기 위해서 통과시킵니다.


2.2 인스턴스 상태

저장 클래스의 인스턴스는 세가지 서로 다른 상태 중에 한가지가 될 수 있으며, 이는 저장 영역(persistence context)에 비추어서 정의됩니다. Hibernate Session 객체는 다음과 같은 저장 영역 상태를 갖습니다.

임의 (transient)

인스턴스는 저장 영역과 관계를 맺지 않고 있는 상태이며, 이전에도 관계를 맺고 있지 않았음.
저장을 위한 식별자(PK 값)를 가지고 있지 않음.

저장 (persistent)

인스턴스는 현재 저장 영역과 관계를 맺고 있음. 저장을 위한 식별자 (PK 값)와, 
DB의 관련 행을 가지고 있음. 특정 저장 영역에 대해서, Hibernate는 저장 식별자는 
자바 식별자 (객체의 내장 메모리 위치)와 동일함을 보장함.

저장 격리 (detached)

인스턴스는 한때 저장 영역과 관계를 맺었지만, 저장 영역은 닫혔거나 인스턴스가 
다른 프로세스로 직렬화되었음. 저장 식별자를 가지고 있으며, DB의 관련 행을 가짐.
저장 격리 인스턴스에 대해서 Hibernate는 저장 식별자와 자바 식별자 간의 관계에 대해서 
보장하지 못함.


2.3 JMX 통합

JMX는 자바 컴포넌트에 대한 관리를 위한 J2EE 표준입니다. Hibernate는 JMX 표준 서비스를 통해서 관리될 수 있습니다. 배포판에 org.hibernate.jmx.HibernateService 에 MBean 구현체를 제공합니다.

JBoss 어플리케이션 서버에 JMX 서비스로 Hibernate가 어떻게 배포되는지에 대한 예제는 JBoss 사용자 가이드를 참고하세요. JBoss AS에서 JMX를 사용해서 배포한다면 다음과 같은 장점을 갖게 됩니다.

* 세션 관리 : Hibernate Session의 생명주기는 자동으로 JTA 트랜잭션의 범위에 놓임.
이는 수동으로 Session을 열고 닫을 필요가 없으며, JBoss EJB 인터셉터의 역할이 됨을 의미함.
코드에서 트랜잭션 선언에 대해서도 더 이상 신경쓸 필요가 없음. (물론 이동이 가능한 
저장 레이어를 작성하지 않는 이상. 이에 대해서는 선택적인 Hibernate Transaction API를 사용함.)
Session에 접속하기 위해서 HibernateContext를 호출함.
* HAR 배포 : 보통은 JBoss 서비스 배포 디스크립터 (EAR이나 SAR 파일 내)를 사용해서 Hibernate JMX 서비스를 배포하며, 
Hibernate SessionFactory의 일반적인 설정 옵션을 모두 지원함. 하지만, 배포 디스크립터에서 
모든 맵핑 파일을 여전히 기입해야 함. 만일 선택적인 HAR 배포를 사용한다면, 
JBoss는 HAR 파일 내의 모든 맵핑 파일을 자동으로 감지함.

위와 같은 설정에 대한 더 많은 정보는 JBoss AS 사용자 가이드를 참고하세요.

JMX 서비스로 가능한 또 다른 기능은 Hibernate 통계입니다. 3.4.6 "Hibernate 통계"를 참고하세요.


2.4 JCA 지원

Hibernate는 JCA 연결로 설정될 수도 있습니다. 더 자세한 정보는 웹사이트를 참고하세요. Hibernate JCA 연결은 아직 시험 중이라는 것을 염두해두시기 바랍니다.


2.5 영역 세션 (Contextual Session)

Hibernate를 사용하는 대부분의 어플리케이션들은 "영역" 세션이라는 특정 형태를 필요로 하며, 이는 주어진 세션이 특정 영역 범위를 통해서 유효한 것을 말합니다. 하지만, 어플리케이션들 간에 영역(context)가 어떻게 구성되었는지에 대한 정의는 일반적으로 다르며, 서로 다른 영역들은 현재의 개념에 대해서 서로 다른 범위를 정의합니다. 3.0 이전의 Hibernate를 사용하는 어플리케이션들은 HibernateUtil 과 같은 helper 클래스인 직접 만든 ThreadLocal 기반 영역 세션을 사용하거나, 프록시/인터셉션 기반 영역 세션이 제공되는 제삼의 프레임워크(Spring이나 Pico)를 사용하기도 했습니다.

버전 3.0.1 에서부터 Hibernate는 SessionFactory.getCurrentSession() 메소드를 추가했습니다. 처음에 이는 현재 세션의 범위와 영역을 모두 정의하는 JTA 트랜잭션을 사용하는 것으로 고안했습니다. Hibernate 팀은 이를 유지했고, 수많은 독자적인 JTA TransactionManager 구현체가 성숙도를 높이면서 많이 출시되는 환경에서 대부분 어플리케이션들은 J2EE 컨테이너로 배포되든 그렇지 않든 간에 상관없이 JTA 트랜잭션 관리를 사용해야만 합니다. 그러한 근거로 JTA 기반 영역 세션은 사용시 필요한 모든 것입니다.

하지만, 3.1 버전에서 SessionFactory.getCurrentSession() 에서의 프로세싱은 이제 플러그인 형태가 되었습니다. 결국, 새로운 확장 인터페이스 (org.hibernate.context.CurrentSessionContext)와 새로운 설정 파라미터 (hibernate.current_session_context_class)가 정의하는 현재 세션의 범위와 영역에 대한 플러그인을 가능하게 하기 위해 추가되었습니다.

좀 더 세부적인 내용에 대해서는 org.hibernate.context.CurrentSessionContext 대한 Javadoc을 참조하세요. 이 인터페이스는 currentSession() 인 단일 메소드를 정의하고 있는데, 현재 영역 세션을 추적하는 역할을 담당합니다. 결국, Hibernate는 이 인터페이스의 다음의 세가지 구현체를 포함합니다.

* org.hibernate.context.JTASessionContext - JTA 트랜잭션에 의해서 현재 세션이 추적되고 범위가 지정됨.
여기서의 프로세싱은 기존의 JTA만을 사용한 방법과 정확하게 동일함.
자세한 사항은 Javadoc 참조.

* org.hibernate.context.ThreadLocalSessionContext - 현재 세션은 실행되는 쓰레드에 의해서 추적됨.
자세한 사항은 Javadoc 참조.

* org.hibernate.context.ManagedSessionContext - 현재 세션은 실행되는 쓰레드에 의해서 추적됨.
하지만, 이 클래스의 정적 메소드를 통해 Session 인스턴를 바인딩하고 바인딩을 하지낳게 할 수 있으며,
절대로 Session을 열거나(open), flush, 혹은 닫지(close) 않음.

처음 두개의 구현체는 "하나의 세션 - 하나의 DB 트랜잭션" 프로그래밍 모델을 제공하며, 세션 당 요청(session-per-request)로 알려지고 사용됩니다. Hibernate 세션의 처음과 끝은 DB 트랜잭션의 주기에 의해 정의됩니다. 만일 JTA 없이 일반적인 JSE 에서 프로그램으로 트랜잭션을 선언하는데 사용하려면, 코드로부터 내부의 트랜잭션 시스템을 감추기 위해 Hibernate 의 Transaction API를 사용하기를 권합니다. JTA를 사용한다면, 트랜잭션 선언을 하는 JTA 인터페이스를 사용하세요. 만일 CMT를 지원하는 EJB 컨테이너에서 실행한다면 트랜잭션 영역은 선언적으로 정의되며 코드에서 트랜잭션이나 세션 선언 행위가 전혀 필요없습니다. 더 많은 정보와 코드 예제는 11장. 트랜잭션과 동시성을 참고하세요.

hibernate.current_session_context_class 설정 파라미터는 어떤 org.hibernate.context.CurrentSessionContext 구현체를 사용하는지를 정의합니다. 만일 이 설정 파라미터가 세팅되지 않고 org.hibernate.transaction.TransactionManagerLookup 가 설정되어 있다면 Hibernate는 org.hibernate.context.JTASessionContext를 사용한다는 것에 유의하세요. 일반적으로 이 파라미터의 값은 사용할 구현 클래스의 이름만을 지정합니다. 하지만, 위의 세가지 구현체에 대해서는 "jta", "thread", "managed" 라는 짧은 이름이 있습니다.