IT한 것/java

EnterpriseJavaBean 3.0 소개

lovian 2006. 4. 21. 16:10
Introduction to Enterprise JaveBeans 3.0
by Lynn Munsinger

EJB 3.0 specification는 과거보다 더 쉽게 Enterpsise JavaBens을 개발할 수 있게 해준다. 아마도 처음으로 EJBs 개발을 하는 사람이라면 기쁜 소식일 것이다. 만일 그러한 경우라면, 축하한다, 당신은 과거 EJB 개발자들 겪은 수많은 난관을 더이상 겪지 않아도 된다, 그리고 EJB 3.0 개발의 간편함을 즐길 수 있다. 그렇지만 개발을 시작하기 전에, 당신이 Enterprise JaveBeans가 무엇인지 이것들을 제공하는 목적이 무엇인지 알고싶을 수도있다. 이 글은  EJBs의 기본과 J2EE 어플리케이션에서 어떻게 활용될 수 있는지를 설명한다.

EJB가 무엇인가?
Enterprise JavaBeans(EJB, 업무용 자바빈???)은 재사용이 가능하고 포터블한 J2EE 컴포넌트이다. EJB는 비즈니스 로직을 캡슐화하는 메서드로 구성된다. 예를들어, 한 EJB는 데이터베이스에 있는 고객 데이터를 갱신하는 메서드를 포함한 비즈니스 로직을 가지고 있을 수도 있다. 다양한 원격, 로컬 클라이언트들은 이 메소드를 실행시킬 수 있다. 추가로 EJB들은 컨테이너 내부에서 실행되고, 트랜젝션 지원, 보안, 원격 객체 접근 같은 복잡하고 에러를 유발하기 쉬운(error prone) 이슈에 대한 고민을 가질 필요 없는 빈을 포함하는 비즈니스 로직만 개발자가 집중할수 있게 만들어준다. EJB들은 POJO(Plain Old Java Object)들로서 개발되었다. 그리고 개발자들은 그러한 빈들이 어떻게 관리될지 명시하기 위해서 메타데이타 어노테이션(Metadata annotation)을 사용할 수 있다.

EJB의 종류
EJB는 세가지 종류가 있다 : Session, Entity,Message-Driven. Session 빈은 고객의 신용기록 검사 같은 독립된 작업을 수행한다.  Entity 빈은데이터베이스에 있는 비지니스 객체를 나타내는 복합 비지니스 개체이다. Message-Driven 빈은 JMS 메시지를비동기적으로 받을 때 사용된다. 그럼 이것들을 아래에서 사용해보자.

Session 빈
Session 빈은 일반적으로 프로세스 정렬 등의 비즈니스 프로세스의 작업을 한다. Session 빈들은 Stateful 또는 Stateless 중 어떤 통신상태가 유지되는가를 기준으로 분류될 수 있다.

Stateless Session 빈은 내부의 상태를 가지지 않는다. 한 메소드로부터 다른 메소드로 지나가는 정보들의 흔적을저장하지 않는다. 그 결과, Stateless 비지니스 메소드의 각 요청은 그 이전의 요청에 독립적이다 ; 예를 들자면세금계산, 화물 선적. 세금을 계산을 하기 위한 메서드가 어떠한 과세 값과 함께 요청될 때, 그 세금값은 계산되고, 다음 요청을위한 호출자의 내부상태를 기록할 필요없이 호출한 메서드에게 반환된다. 상태를 저장하지 않기 때문에, 이러한 빈들은 컨테이너가관리하기에 간편하다. 클라이언트가 Stateless 빈 인스턴스를 요청할 때, 컨테이너에 의해 관리되는 'StatelessSession 빈 인스턴스의 풀'에서     인스턴스를 가져올 수도 있다. 또한, Stateless Session 빈은 공유될 수 있기때문에, 컨테이너는 다수의 클라이언트에게 제공하기 위한 적은 수의 인스턴스를 가진다. Java 빈이 StatelessSession 빈으로써 디플로이 되고 관리되는 것을 설명하자면, 간단히 해당 빈에 '어노테이션 @Stateless' 을 추가하라.

Stateful Session 빈은  메소드 호출에 사용되는 상태 데이터(state)를 가지고 있다 ; 예를 들면 고객의 온라인 쇼핑카트. 이 고객이 온라인 쇼핑을 시작할 때, 데이터베이스에서 이 고객의 신상자료를 읽어온다. 이 신상자료들은 '그 고객이 물건을 카트에 추가하거나 카트로부터 제거 또는 주문할때' 요청하는 또 다른 메서드도 사용할 수 있다. 그렇지만 Stateful Session 빈은 그 상태 데이터는 세션종료, 시스템 붕괴 또는 네트윅 문제시 더이상 유효하지 않기 때문에 휘발성을 가진다. 어떤 클라이언트가 Stateful Session 빈 인스턴스를 요구하였을 때, 한 Stateful 인스턴스가 할당되고 그 빈의 상태 데이터는 그 클라이언트를 위해 지속관리된다. 어떤 메서드가 완료되면 컨테이너에서 제거되는 Stateful Session 빈 인스턴스를 표시하기 위해 그 메서드에 어노테이션 @Remove을 추가한다.

Session 빈 예제
[CODE] 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"; } } [/CODE]

Entity Beans

Entity 빈은 영속적인 데이터를 관리하는 객체이다. 그리고 다수의 의존성을 가진 자바 객체들을 잠정적으로 사용할수 있고, 기본키로 유일하게 식별될 수 있다. 어노테이션 @Entity를 사용하여 어떤 클래스가 Entity 빈 인 것을 명시하라. Entity 빈들은 데이터베이스의 고객테이블의 한 열, 또는 직원테이블의 한 레코드 같은 영속적 데이터를 나타낸다. 또한 Entity 빈들은 다수의 클라이언트간에 공유될 수 있다. 예를들어 직원 Entity 빈은 직원의 연봉 계산이나, 직원 거주지 주소의 갱신을 위해 다양한 클라이언트로부터 사용될 수 있다. Entity 빈 객체의 세부 항목은 영속적으로 만들어진다. 어노테이션 @Transient로 표시되지 않은 Entity 빈의 모든 항목은 영속적임을 고려해야한다. EJB 3.0의 주요 특징은 metadata 어노테이션을 사용한 객체/관계를 가지는 Entity 빈을 만드는 능력이다. 예를들어 어떤 Entity 빈의 empId 항목을 표시하기위한 방법이 직원 테이블의 EMPNO 속성에 매핑이다. 그 방법은 아래의 예제에서 보여주듯이 @Table(name="Employees")을 이용하여 테이블 이름과 @Column(name="EMPNO")를 이용하여 항목에 대한 주석을 다는 것(annotate)이다. 추가로 EJB 3.0의 특별한 기능은 외부 컨테이너에서 작동중인 Entity 빈이 Oracle Application Server Entity Test Harness를 사용하는 것이 현재 가능하기 때문에 개발하는 동안에 Entity 빈들의 검사가 용이하다는 점이다.

Entity 빈 예제

[CODE] 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(); } } [/CODE]

MessageDriven Beans
Message-driven Beans(MDBs)는 비동기적인 통신을 구현하는데에 있어서 수직적인 Jave Message Service를 사용하는 방법 보다 더 쉬운 방법을 제공한다. MDBs 비동기적인 JMS 메시지를 받기위해 만들어졌다. 그 컨테이너(무슨 컨테이너???)는 JMS queues나 topics들을 필요로하는 설정과정들의 대부분을 조절한다. 이 컨테이너는 관련있는 MDB(interested MDB)에게 모든 메시지를 전송한다. 어떤 MDB는 J2EE 어플리케이션이 그 어플리케이션에 의해 수행될 수 있는 비동기적인 메시지들를 전송할 수 있게 한다. 어떤 빈이 MDB임을 명시하려면, javax.jms.MessageListener 인터페이스를 구현하고 @MessageDriven 주석을 달라.

MessageDriven Bean Example

[CODE] 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'") } ) /** * A simple Message-Driven Bean that listens to the configured JMS Queue or Topic and gets notified via an * invocation of it's onMessage() method when a message has been posted to the Queue or Topic. The bean * prints the contents of the message. */ 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; } } [/CODE]


EJBs의 활용하기
어떤 EJB 클라이언트는 그 빈에 접근하는 어플리케이션이다. 그 클라이언트는 클라이언트 단(tier)에 위치할 당위성은 없고, standard-alone application, JSP, servlet, 또다른 EJB일 수 있다. 그 클라이언트는 자신이 그 빈과 동일하거나 다른 위치에 있는 JVM에 있는가와 상관없이  그 빈의 원격, 로컬 인터페이스를 통해서 어떤 EJB의 메서드들에 접근한다. 그 빈 클래스가 그 메서드들을 실제로 구현하는 반면에 이러한 인터페이스들은 그 메서드들을 정의한다. 어떤 클라이언트가 그 빈 클래스의 어떠한 메서드에 접근하였을 때, 그 컨테이너는 원격 혹은 로컬 객체라 불리우는 그 빈의 대리자(proxy)를 생성한다. 그 원격, 로컬 객체는 그 요청을 받고, 관련있는 빈의 인스턴스에게 요청을 위임한다. 그리고 클라이언트에게 그 결과를 반환한다. 어떠한 빈의 메서드들을 실행하기 위해서, 어떠한 클라이언트는 EJB deployment descriptor에 정의된 빈의 이름을 사용해서 그 빈을 찾을 수 있다. 아래의 예제에서 그 클라이언트는 Context 객체를 사용해서 Statelessejb 라 이름지어진 빈을 찾는다.

EJB Client Example

[CODE] import javax.naming.Context; import javax.naming.InitialContext; /** * A simple bean client which calls methods on a stateless session bean. */ 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(); } } [/CODE]

요약
Enterprise JaveBeans를 개발하는 것은 EJB 3.0 specification을 이용하는 방법이 분명히 더 쉽다. 그 명세(specification)는 빈의 형태와 클라이언트에게 노출되는 메소드들을 정의하기 위해 metadata annotaions를 사용한다. 그러므로 특정 작업을 실행하기 위해 세션빈을 생성하거나 또는 데이터 갱신을 위해 어떠한 엔티티 빈에 테이블을 매핑하던간에  plain java object와 인터페이스를 사용하거나 그 비즈니스 메서드들 없이 어노테이션에 의해서 클라이언트에게 메소드들은 노출시킬 수 있다. EJBs의 기본 이해를 했고, 더 많은 정보를 원한다면 OTN's EJB 3.0 Resorces Page를 참고하라.


번역완료

참고:
어노테이션 > Java 1.5 에서 추가된 기능.

원문 : http://www.oracle.com/technology/tech/java/newto/introejb.htm