본문 바로가기

자바스토리

EJB 3.0 설명

Enterprise JavaBeans 3.0 소개

저자 – Lynn Munsinger

EJB 3.0 표준이 발표되면서, Enterprise JavaBeans를 이용한 개발 작업이 그 어느 때보다도 쉬워졌습니다. 덕분에 EJB를 처음으로 구현해 보려는 개발자들의 수도 늘고 있습니다. EJB를 처음 접하는 개발자들에게 먼저 축하 드린다는 말씀을 드리고 싶습니다. 과거 EJB 개발자들이 겪어야 했던 어려움 없이 이제 쉽게 EJB 3.0 환경을 개발하실 수 있게 되었기 때문입니다. 하지만 개발을 시작하기에 앞서, Enterprise JavaBeans가 무엇이고 어떤 목적으로 활용되는지 알아 둘 필요가 있습니다. 본 문서는 EJB의 기본 개념과 EJB를 J2EE 애플리케이션에서 활용하는 방법을 설명하고 있습니다.

EJB란 무엇입니까?

Enterprise JavaBean(EJB)은 재활용 가능한 포터블 J2EE 컴포넌트입니다. EJB는 비즈니스 로직을 인캡슐레이트 하는 메소드들로 구성되어 있습니다. 한 예로, EJB가 데이터베이스의 고객 데이터 업데이트를 위한 메소드를 포함하는 비즈니스 로직을 구현하고 있을 수 있습니다. 다양한 원격/로컬 클라이언트에서 이 메소드를 호출하는 것이 가능합니다. 또 EJB는 컨테이너 내부에서 실행되므로, 개발자들이 트랜잭션 지원, 보안, 원격 오브젝트 접근과 같은 복잡하고 까다로운 문제를 신경 쓰지 않고도 빈 내부에 포함된 비즈니스 로직에만 집중할 수 있게 합니다. EJB는 POJO(Plain Old Java Object)의 형태로 개발되며, 개발자들은 메타데이터 주석(metadata annotation)을 이용하여 이 빈들이 어떻게 관리되는지 정의할 수 있습니다.

EJB의 여러 가지 타입

EJB는 기본적으로 Session, Entity, Message-Driven의 세 가지 타입으로 구성됩니다. Session 빈은 개별적이고 디커플링된 작업을 수행합니다(예: 고객의 신용 기록 조회). Entity 빈은 데이터베이스에 존재하는 비즈니스 오브젝트를 기반으로 하는 복잡한 형태의 비즈니스 엔티티입니다. Message-Driven 빈은 비동기식 JMS 메시지를 수신하기 위해 사용됩니다. 각각의 EJB 타입에 대해 자세히 살펴 보겠습니다.

Session Beans

세션 빈은 일반적으로 "프로세스 순서"와 같은 비즈니스 프로세스 액션을 구현하는 용도로 사용됩니다. 세션 빈은 커뮤니케이션 상태 정보의 관리 방법에 따라 "stateful"과 "stateless"로 구분됩니다.

"Stateless" 세션 빈은 내부 상태 정보를 갖고 있지 않습니다. "Stateless" 세션 빈에서는 특정 메소드에서 다른 메소드로 전달되는 정보가 추적되지 않으며, 따라서 각각의 비즈니스 메소드 호출은 이전의 호출과 독립적으로 수행됩니다. 세금을 계산하거나 배송료를 계산하는 경우가 그러한 예입니다. 특정 값에 대한 세금을 계산하는 메소드가 호출되면, 세금 결과값이 계산되어 호출한 메소드로 반환됩니다. 이 과정에서 호출 메소드의 내부 상태 정보는 저장되지 않습니다. 이처럼 상태 정보가 유지되지 않으므로 컨테이너에서 세션 빈을 관리하는 작업이 단순화됩니다. 클라이언트가 "stateless" 빈 인스턴스를 호출하면, 컨테이너가 관리하는 "stateless" 세션 빈 인스턴스의 풀로부터 인스턴스가 전달됩니다. 또 "stateless" 세션 빈은 공유가 가능하므로, 컨테이너는 보다 적은 수의 인스턴스로 다수의 클라이언트에 서비스를 제공할 수 있습니다. Java Bean이 "stateless" 세션 빈으로 구현/관리되도록 지정하려면, 빈에 @Stateless 주석을 추가하기만 하면 됩니다.

"stateful" 세션 빈은 메소드 호출 과정에서 상태 정보를 유지합니다. 고객의 온라인 장바구니가 좋은 예입니다. 고객이 온라인 쇼핑을 시작하면, 고객의 상세 정보가 데이터베이스로부터 조회됩니다. 고객이 장바구니에서 아이템을 추가/삭제할 때, 또는 주문을 실행할 때 호출되는 다른 메소드들도 동일한 고객 정보를 공유할 수 있습니다. 하지만 "stateful" 세션 빈의 상태 정보는 세션 종료, 시스템 다운, 네트워크 장애 시에는 보존되지 않습니다. 클라이언트가 "stateful" 세션 빈 인스턴스를 요청하면, 클라이언트는 특정 "stateful" 인스턴스에 할당되며 해당 클라이언트의 빈 상태 정보가 관리됩니다. 특정 메소드가 완료된 이후 "stateful" 세션 빈 인스턴스를 제거하려는 경우, 메소드에 @Remove 주석을 추가해 주면 됩니다.

Session Bean 예제

import javax.ejb.Stateless.*;

/**
* A simple stateless session bean implementing the incrementValue() method of the * CalculateEJB interface.
*/

@Stateless(name="CalculateEJB")
public class CalculateEJBBean 
implements CalculateEJB
{
int value = 0;
public String incrementValue()
{
value++; 
return "value incremented by 1";
}
}

 

Entity Beans

엔티티 빈은 다양한 종속 Java 오브젝트를 이용하여 퍼시스턴트 데이터를 관리하는 오브젝트로, 프라이머리 키(primary key)를 기준으로 유니크하게 참조될 수 있습니다. 특정 클래스를 엔티티 빈으로 지정하려면 @Entity 주석을 사용합니다. 엔티티 빈은 고객 테이블의 특정 로우, 또는 직원 테이블의 특정 직원 레코드 등 데이터베이스에 저장된 퍼시스턴트 데이터에 대응됩니다. 엔티티 빈은 또 다수의 클라이언트에 의해 공유될 수 있습니다. 예를 들어, employee 엔티티 빈은 직원의 연봉을 계산하는 클라이언트와 직원의 주소를 업데이트하는 클라이언트에 의해 동시에 사용될 수 있습니다. 또 엔티티 빈 오브젝트의 특정 필드에 "persistent" 속성을 지정할 수 있습니다. 엔티티 빈에서 @Transient 주석이 표시되지 않은 모든 필드는 "persistent" 속성을 갖는 것으로 간주됩니다. EJB 3.0은 메타데이터 주석을 이용하여 오브젝트/관계형 매핑을 포함하는 엔티티 빈을 생성하는 기능을 제공하고 있습니다. 예를 들어 특정 엔티티 빈의 empId 필드가 Employee 테이블의 EMPNO 컬럼에 대응되도록 지정하려면, 아래 예제와 같이 테이블 이름에 @Table(name="Employees") 주석을, 필드 네임에 @Column(name="EMPNO") 주석을 달면 됩니다. 또 EJB 3.0은 개발 과정에서 엔티티 빈을 쉽게 테스트할 수 있는 기능을 지원하고 있습니다.

Entity Bean 예제

import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collection;

@Entity
@Table(name = "EMPLOYEES")
public class Employee implements java.io.Serializable
{
private int empId;
private String eName;
private double sal;

@Id
@Column(name="EMPNO", primaryKey=true)
public int getEmpId()

return empId;
}

public void setEmpId(int empId) 

this.empId = empId; 
}

public String getEname() 

return eName; 
}

public void setEname(String eName) 

this.eName = eName; 
}

public double getSal() 

return sal; 
}


public void setSal(double sal) 

this.sal = sal; 
}

public String toString()
{
StringBuffer buf = new StringBuffer();
buf.append("Class:")
.append(this.getClass().getName()).append(" :: ").append(" empId:").append(getEmpId()).append(" ename:").append(getEname()).append("sal:").append(getSal());
return buf.toString();
}
}

 

Message-Driven Beans

Message-driven Bean(MDB)를 이용하면 기존의 JMS(Java Message Services)를 이용하던 방법에 비해 훨씬 간편하게 비동기식 커뮤니케이션을 구현할 수 있습니다. MDB는 비동기식 JMS 메시지를 수신하기 위한 용도로 구현됩니다. 컨테이너는 JMS 큐 및 토픽에 요구되는 대부분의 셋업 프로세스를 처리하고 모든 메시지를 대상 MDB로 전달합니다. MDB를 이용하면 비동기식 메시지를 J2EE 애플리케이션에 전달하여 처리하도록 하는 것이 가능합니다. 빈을 MDB로 지정하려면 javax.jms.MessageListener 인터페이스를 구현하고 빈에 대해 @MessageDriven 주석을 추가해 줍니다.

Message Driven Bean 예제

import javax.ejb.MessageDriven;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.Inject;
import javax.jms.*;
import java.util.*;
import javax.ejb.TimedObject;
import javax.ejb.Timer;
import javax.ejb.TimerService;
@MessageDriven(
activationConfig = {
@ActivationConfigProperty(propertyName="connectionFactoryJndiName", propertyValue="jms/TopicConnectionFactory"),
@ActivationConfigProperty(propertyName="destinationName", propertyValue="jms/myTopic"),
@ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Topic"),
@ActivationConfigProperty(propertyName="messageSelector", propertyValue="RECIPIENT = 'MDB'")

}
)

/**
* 설정된 JMS Queue 또는 Topic을 리스닝하고 메시지가 Queue 또는 Topic에 포스트 된 경우 * onMessage() 메소드를 통해 통보를 전달 받는 간단한 Message-Driven Bean 예제. 
이 빈은 메시지 내용을 출력함.
*/

public class MessageLogger implements MessageListener, TimedObject
{

@Inject javax.ejb.MessageDrivenContext mc;

public void onMessage(Message message)
{
System.out.println("onMessage() - " + message);
try
{
String subject = message.getStringProperty("subject");
String inmessage = message.getStringProperty("message");
System.out.println("Message received\n\tDate: " + new java.util.Date() + "\n\tSubject: " + subject + "\n\tMessage: " + inmessage + "\n");
System.out.println("Creating Timer a single event timer");
TimerService ts = mc.getTimerService();
Timer timer = ts.createTimer(30000, subject);
System.out.println("Timer created by MDB at: " + new Date(System.currentTimeMillis()) +" with info: "+subject);

catch (Throwable ex) 

ex.printStackTrace(); 
}
}

public void ejbTimeout(Timer timer)
{
System.out.println("EJB 3.0: Timer with MDB");
System.out.println("ejbTimeout() called at: " + new Date(System.currentTimeMillis()));
return;
}

}

 

EJB의 활용

EJB 클라이언트는 빈에 접근하는 애플리케이션입니다. EJB 클라이언트가 반드시 클라이언트 티어에 위치할 필요는 없으며, 스탠드얼론 애플리케이션, JSP, 서브렛 또는 EJB로 구현될 수 있습니다. 클라이언트는 빈의 원격/로컬 인터페이스를 통해 EJB의 메소드에 접근합니다. (클라이언트가 빈과 같은 JVM에 위치한 경우 로컬 인터페이스를, 다른 JVM에 위치한 경우 원격 인터페이스를 사용합니다.) 이 인터페이스는 빈의 메소드를 정의하고 있으며, 메소드는 빈 클래스에 의해 구현됩니다. 클라이언트가 빈 클래스의 메소드에 접근하면, 컨테이너는 빈을 위한 프록시를 생성하며, 이를 원격/로컬 오브젝트라 부릅니다. 요청을 접수한 원격/로컬 오브젝트는, 해당 빈 인스턴스에 요청의 실행을 위임한 후 그 결과를 클라이언트에 반환합니다. 빈의 메소드를 호출하기 위해, 클라이언트는 EJB deployment descriptor에 정의된 이름을 사용하여 빈을 검색합니다. 아래 예제에서 클라이언트는 Context 오브젝트를 사용하여 "Statelessejb"라는 이름의 빈을 검색하고 있습니다.

EJB 클라이언트 예제

import javax.naming.Context;
import javax.naming.InitialContext;

/**
* "stateless" 세션 빈의 메소드를 호출하는 간단한 빈 클라이언트 예제
*/

public class CalculateejbClient 
{
public static void main(String [] args)
{
Context context = new InitialContext();

CalculateEJB myejb =
(CalculateEJB)context.lookup("java:comp/env/ejb/CalculateEJB");
myejb.incrementValue();
}
}

 

요약

EJB 3.0 표준을 이용하면 이전보다 훨씬 간단한 방법으로 Enterprise JavaBean을 구현할 수 있습니다. EJB 3.0은 메타데이터 주석을 사용하여 빈의 타입과 클라이언트에 노출되는 메소드를 정의합니다. 따라서 특정 작업을 실행하기 위해, 또는 데이터 업데이트 과정에서 테이블을 엔티티 빈을 매핑하기 위해 세션 빈을 생성하는 경우에도 POJO 오브젝트와 인터페이스를 사용하고 비즈니스 메소드 내에서 주석을 이용하여 클라이언트에 메소드를 노출할 수 있습니다. 지금까지 EJB의 기본 개념에 대해 설명했습니다. 보다 자세한 정보는 OTN의 EJB 3.0 리소스 페이지를 참고하시기 바랍니다.

'자바스토리' 카테고리의 다른 글

자바 시리얼라이즈(Java Serializatoin)  (0) 2014.03.13
JSP PAGE 지시어 설명  (0) 2014.02.04
MYBATIS  (0) 2013.12.20
개발 관련 url  (0) 2013.11.12
검색엔진 패스트캣  (0) 2013.11.05