EJB(Enterprise Java Beans) 기술의 구성요소에는 세션 빈(session bean), 엔티티 빈(entity bean), 메시지 구동 빈(message-driven bean, MDB) 등의 세 종류가 있다. 상태유지(stateful)와 비상태유지(stateless)가 모두 가능한 세션 빈은 흔히 비즈니스 프로세스를 나타내는데, 상태유지 세션 빈은 일반적으로 한번에 한 클라이언트에 의해 액세스되지만, 상태 유지와 비상태 유지 세션 빈은 모두 동기 방식으로 액세스되며 비영속적이다. 이와 대조적으로 엔티티 빈은 영속적 스토리지에 저장되는 비즈니스 데이터를 나타낸다. MDB는 J2EE 애플리케이션이 JMS(Java Message Service) API를 사용하여 빈과 클라이언트간의 메시지를 비동기적으로 처리할 수 있게 해준다. MDB는 최신 형태의 EJB로, EJB2.0과 함께 도입되었는데, MDB이 도입되면서 J2EE 애플리케이션은 JMS(Java Message Service) API를 사용하여 빈과 클라이언트간의 메시지를 비동기적으로 처리할 수 있게 되었다.
MDB는 여러 면에서 상태유지 세션 빈과 비슷하다. EJB 스펙은 상태유지 세션 빈과 유사한 MDB의 일부 특성을 강조하는 몇 가지 예를 보여주고 있다.
- 메시지 구동 빈의 인스턴스는 특정 클라이언트에 대한 데이터 또는 대화 상태를 유지하지 않는다.
- EJB 컨테이너는 어떤 메시지 구동 빈 인스턴스에도 메시지를 할당할 수 있어 메시지 구동 빈의 인스턴스는 모두 동등하다.
- 컨테이너는 이들 인스턴스를 풀링하여 메시지 스트림이 병렬 처리되도록 할 수 있다.
- 하나의 메시지 구동 빈이 복수 클라이언트의 메시지를 처리할 수 있다.
두 가지 빈 사이의 가장 뚜렷한 차이는 MDB는 동기 메소드 호출(가령 이벤트) 대신 비동기 JMS 메시지를 수신한다는 점이다. 세션 빈과 엔티티 빈은 JMS 메시지를 전송하고 이를 동기적으로 수신할 수 있지만 비동기적으로 수신할 수는 없다. 이들 비동기 메시지는 애플리케이션 클라이언트, 또 다른 엔터프라이즈 빈, 웹 구성요소 등 어떤 J2EE로든 전송이 가능하다. EJB 2.0이 도입되면서 MDB를 구현하기가 간단해졌다. MDB는 JMS 메시지에만 반응하기 때문에 다른 종류의 엔터프라이즈 빈에서 기대되는 것과 같은 클라이언트 인터페이스(client interface)나 홈 인터페이스(home interface)가 필요치 않다. MDB는 JMS 인터페이스 javax.jms.MessageListener와 javax.ejb.MessageDrivenBean 인터페이스를 구현하는 하나의 클래스만을 요구한다. 다음은 MDB의 간단한 예제이다.
import javax.ejb.*;
import javax.jms.*;
public class MyMessageBean implements MessageDrivenBean,
MessageListener
{
public void ejbCreate() throws CreateException {...}
public void ejbRemove() { ... }
public void setMessageDrivenContext(
MessageDrivenContext ctx) { ... }
public void onMessage(Message msg) { ... }
}
클라이언트 구성요소는 MDB를 찾아서 그곳에서 직접 메소드를 호출하지 않는다. 대신 클라이언트는 MDB 클래스가 MessageListener인 메시지 수신지에 메시지를 전송함으로써 JMS를 통해 MDB에 액세스합니다. 다음은 J2EE 1.4 Tutorial의 MDB 예제를 기초로 한 예제이다. MDB에 메시지를 전송하기 위해 클라이언트는 먼저 커넥션 팩토리 (connection factory)와 큐(queue)를 만든다.
connectionFactory =
(ConnectionFactory) jndiContext.lookup(
"java:comp/env/jms/MyConnectionFactory");
destination =
(Queue) jndiContext.lookup("java:comp/env/jms/QueueName");
다음으로, 클라이언트는 큐 커넥션, 세션, 송신자를 생성한다.
connection = connectionFactory.createConnection();
session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageProducer = session.createProducer(destination);
message = session.createTextMessage();
마지막으로, 클라이언트가 큐에 메시지를 보낸다.
for (int i = 0; i < NUM_MSGS; i++) {
message.setText("This is message " + (i + 1));
System.out.println("Sending message: " +
message.gettext());
messageProducer.send(message);
}
큐가 메시지를 수신할 경우 EJB 컨테이너는 MDB의 onMessage() 메소드를 호출하는데, 이 메소드는 메시지의 프로세싱을 처리하는 비즈니스 로직을 포함하고 있다. 메시지를 파싱하고 필요한 비즈니스 로직을 수행하는 것은 MDB의 책임이다. MyMessageBean의 경우, onMessage() 메소드는 들어오는 메시지를 TextMessage로 캐스트하고 텍스트를 로그 파일에 보낼 수 있었다.
public void onMessage(Message inMessage) {
TextMessage msg = null;
try {
if (inMessage instanceof TextMessage) {
msg = (TextMessage) inMessage;
logger.info("MESSAGE BEAN: Message received: " +
msg.getText());
} else {
logger.warning("Message of wrong type: " +
inMessage.getClass().getName());
}
} catch (JMSException e) {
e.printStackTrace();
} catch (Throwable te) {
te.printStackTrace();
}
}
EJB 2.1에서 새로워진 내용
EJB 2.1을 도입하면 더 이상 JMS 사용에 구애를 받지 않아도 되는데, MDB를 웹 서비스에 연결하고자 하는 프로그래머에게는 이런 변화가 매우 중요하다. 이제는 적절한 인터페이스를 구현함으로써 MDB가 다른 종류의 메시지를 청취하도록 할 수 있다. 이 인터페이스는 통상적으로 J2EE 커넥터 아키텍처를 따르는 ‘커넥터(connector)’를 사용하여 추가된다. J2EE 커넥터 아키텍처 1.5는 특별히 MDB에 맞추어진 메시징 계약을 정의한다. (2004년 12월 15일자 테크팁 J2EE 커넥터 아키텍처 1.5 참조).
비동기 커넥터를 기반으로 한 MDB는 표준 javax.ejb.MessageDrivenBean 인터페이스를 구현하며, 아울러 Enterprise Information System 특유의 커넥터 자체에 의해 정의되는 특정한 메시징 인터페이스를 구현한다.
웹 서비스 커넥터와 관계된 간단한 예를 살펴보자. 커넥터 소프트웨어는 RAR(Resource Archive) 파일에 상주하고, 이 RAR는 또한 개발자가 웹 서비스 MDB를 생성하기 위해 사용하는 메시징 인터페이스와 메시징 API를 정의한다. 다음은 EJB 2.1 MDB가 반드시 구현해야 하는 가정적인 인터페이스이다.
package com.someone.web;
public interface WebServiceListener {
public void receiveWebServiceMessage(
XMLDocument message);
}
이 경우 MDB는 javax.ejb.MessageDrivenBean 인터페이스와 WebServiceListener 인터페이스를 모두 구현하게 된다. 다음 코드는 WebServiceListener 인터페이스를 구현하여 XML 메시지를 처리하는 MDB를 보여준다.
package com.someone.web;
public class WebServiceBean implements
javax.ejb.MessageDrivenBean,
com.someone.web.WebServiceListener
{
MessageDrivenContext ejbContext;
public void setMessageDrivenContext(
MessgeDrivenContext context){
ejbContext = context;
}
public void ejbCreate()
{
// Code omitted
}
public void receiveWebServiceMessage(
XMLDocument message)
{
// Do something with message
}
public void ejbRemove(){
// code omitted
}
}
사용되는 메시징 인터페이스가 리턴 타입을 정의하는 메소드를 선언할 수 있다는 데 유의하길 바란다. 이번에도 커넥터가 반드시 개입하여 회신 메시지를 다시 송신자에게 중계해야 한다.
배치 서술자 변경
EJB 2.1에서는 MDB를 위한 배치 서술자(deployment descriptor)가 상당수 변경되었다. 이들은 더 이상 JMS에만 전적으로 의존하지 않기 때문에 EJB 2.1에서는 <message-selector>와 <acknowledge-mode>엘리먼트가 교체되었습니다. 이와 더불어, MDB의 다양한 속성을 열거하기 위해 message-agnostic 엘리먼트인 <activation-config>가 도입되었다. <activation-config>의 속성들은 메시지 구동 빈이 배치될 때 커넥터에 전달된다.
다음은 몇 가지 <activation-config> 속성 설정의 예이다.
<activation-config>
<activation-property>
<activation-config-property-name>messageSelector
</activation-config-property-name>
<activation-config-property-value>Priority = 'Urgent'
</activation-config-property-value>
<activation-property>
</activation-config>
EJB 2.1은 JMS 기반 MDB에 대해 다음 4개의 고정 속성을 정의하며, 이들은 이전의 EJB 2.1 속성을 대체한다.
acknowledgeMode
messageSelector
destinationType
subscriptionDurablity
EJB 2.1은 또한 다음과 같이 두 개의 새로운 엘리먼트, <messaging-type>과 <message-destination-type>을 추가한다.
<messaging-type>javax.jms.MessageListener
</messaging-type>
<message-destination-type>
javax.jms.Queue
</message-destination-type>
<messaging-type> 엘리먼트는 fully-qualified 인터페이스명을 지정함으로써 어떤 메시지 타입을 사용하게 될지를 나타낸다. 인터페이스명이 주어지지 않을 경우 컨테이너는 기본값으로 javax.jms.MessageListener로 정해진다. <message-destination-type> 엘리먼트는 빈이 메시지를 받게 될 수신지의 타입을 나타내는 fully-qualified 클래스를 지정한다. JMS의 경우, 허용된 값은 javax.jms.Queue 와 javax.jms.Topic이다.
메시지 링크
어떤 타입의 EJB도 메시지를 전송할 수 있는 MDB 수신지를 명시하기 위해 배치 서술자에 메시지 링크 기능이 추가되었다. ejb-refs를 사용하고 있다면 전송하는 빈에 대한 배치 서술자의 변경에 익숙할 것이다.
<session>
<ejb-name>SendingEJB</ejb-name>
<resource-ref>
<res-ref-name>jms/MyFactory</res-ref-name>
<res-type>javax.jms.MyConnectionFactory</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<message-destination-ref>
<message-destination-ref-name>
jms/MyDestination
</message-destination-ref-name>
<message-destination-type>
javax.jms.Topic
</message-destination-type>
<message-destination-usage>
Produces
</message-destination-usage>
<message-destination-link>
MyDestinationLink
</message-destination-link>
</message-destination-ref>
</session>
수신하는 MDB의 경우, 배치 서술자 정보에 다음이 포함되어야 한다.
<message-driven>
<ejb-name>ReceivingEJB</ejb-name>
<messaging-type>
javax.jms.MessageListener
</messaging-type>
<transaction-type>Bean</transaction-type>
<message-destination-type>
javax.jms.Topic
</message-destination-type>
<message-destination-link>
MyDestinationLink
</message-destination-link>
</message-driven>
송수신 빈을 링크하기 위해, 어셈블리 서술자에 다음이 표시되어야 한다.
<assembly-descriptor>
<message-destination>
<message-destination-name>
MyDestinationLink
</message-destination-name>
</message-destination>
</assembly-descriptor>
메시지 구동 빈에 관한 자세한 내용을 보려면 J2EE 1.4 Tutorial을 참조하기 바란다.
"Java EE" 카테고리의 다른 글
- Attach API (댓글 18개 / 트랙백 1개) 2007/09/03
- JSP 2.0 EXPRESSION LANGUAGE (댓글 1개 / 트랙백 0개) 2004/02/05
- 환경 엔트리를 이용해서 배포의 사용자 정의하기 (댓글 2개 / 트랙백 0개) 2003/12/24
- JAX-WS를 이용한 웹 서비스 개발 (댓글 1개 / 트랙백 0개) 2006/01/18
- EJB 2.1로 메시지 구동 빈 이용하기 (댓글 1개 / 트랙백 0개) 2005/05/18
- EclipseLink를 사용하여 JPA에서 반복 불가능한 읽기 방지 (댓글 0개 / 트랙백 1개) 2008/07/09
- 컴포넌트 시스템과 클래스 로더 경계 (댓글 1개 / 트랙백 0개) 2004/10/05
- JAX-WS Dispatch 및 Provider API를 이용한 문서 처리 (댓글 4개 / 트랙백 0개) 2006/09/15
- POJO를 Persistent Entity로 변환하기 (댓글 1개 / 트랙백 0개) 2005/12/27
- SAAJ 소개 (댓글 1개 / 트랙백 0개) 2005/06/08
댓글을 달아 주세요
좋은 정보 감사해요~
2007/09/19 05:29