SeamFramework.orgCommunity Documentation
JSR-299 has recently changed its name from "Web Beans" to "Java Contexts and Dependency Injection". The reference guide still refers to JSR-299 as "Web Beans" and the JSR-299 Reference Implementation as the "Web Beans RI". Other documentation, blogs, forum posts etc. may use the new nomenclature, including the new name for the JSR-299 Reference Implementation - "Web Beans".
You'll also find that some of the more recent functionality to be specified is missing (such as producer fields, realization, asynchronous events, XML mapping of EE resources).
Web Beans (JSR-299) 사양은 애플리케이션을 보다 쉽게 개발하기 위한 Java EE 환경에 대한 서비스 모음을 정의합니다. Web Beans는 JavaBeans 및 Enterprise Java Bean을 포함하여 기존의 Java 구성 요소 유형을 통해 향상된 수명 주기 및 상호 작용 모델을 계층화합니다. 전통적인 Java EE 프로그래밍 모델의 구성 요소로서, Web Beans는 다음과 같은 서비스를 제공합니다:
명확하게 정의된 컨텍스트에 바인딩된 상태 유지 구성 요소의 수명 주기 개선
의존성 주입 (dependency injection)으로의 타입 안정적 (typesafe) 접근
이벤트 통지 기능을 통한 상호작용
데코레이터 (decorator) 라는 새로운 종류의 인터셉터와 함께 인터셉터를 구성요소에 바인딩하기 위해 개선된 접근으로, 비지니스 문제 해결을 위해 보다 적절하게 사용
컨텍스트 수명 주기 관리와 함께 의존성 주입은 다음과 같은 질문을 묻고 대답하는 것에서 생소한 API 사용자를 보호합니다:
이러한 객체의 수명 주기는 무엇입니까?
얼마나 많은 클라이언트가 이를 동시에 갖을 수 있습니까?
이는 멀티스레드됩니까?
어디서 얻을 수 있을까요?
이를 명시적으로 삭제해야 합니까?
직접 사용하지 않을 경우 참조 사항을 어디에 보관해야 합니까?
어떻게 하면 우회 계층을 추가하여, 배치시 이러한 개체 구현을 다르게 할 수 있을까요?
어떻게 하면 다른 개체 사이에서 이러한 개체를 공유할 수 있을까요?
Web Bean은 의존하는 다른 Web Beans의 유형 및 시멘틱 만을 지정합니다. 이는 의존하는 다른 Web Bean 클라이언트 또는 스레딩 모델, 실제적인 수명 주기, 구체적 구현 방식을 인식할 필요가 없습니다. 더 나아가 의존하는 Web Bean의 스레딩 모델, 수명 주기, 구체적 구현 방식은 클라이언트에게 영향을 미치지 않고 운용 방식에 따라 달라질 수 있습니다.
이벤트, 인터셉터 및 데코레이터는 이러한 모델에 내제된 느슨하게 연결하는 (loose-coupling) 기능을 강화합니다:
이벤트 통지는 이벤트 소비자로부터 이벤트 생산자를 연결 해제합니다
인터셉터는 비지니스 로직으로 부터의 기술적 문제를 연결 해제합니다
데코레이터는 비지니스 문제를 구분하게 합니다.
가장 중요하게 Web Beans는 이러한 모든 기능을 타입 안정적 (typesafe) 방식으로 제공합니다. Web Beans는 협력적 객체를 갖추기 위한 방법을 결정하기 위해 문자열 기반의 식별자를 사용하지 않습니다. XML은 옵션으로 남아있어도 거의 사용되지 않습니다. 대신 Web Beans는 바인딩 어노테이션 (binding annotations)이라는 새로운 패턴과 함께 Java 객체 모델에서 이미 사용 가능한 타이핑 정보를 사용하여 Web Beans 및 Web Beans의 의존성, 인터셉터, 데코레이터 및 이벤트 소비자를 함께 묶습니다.
Web Beans 서비스는 일반적으로 Java EE 환경에 있는 다음과 같은 구성 요소의 유형에 적용됩니다:
모든 JavaBeans
모든 EJB
모든 Servlets
Web Beans는 통합 지점을 제공하여 차후 Java EE 사양이나 또는 비표준 프레임워크에 의해 지정된 다른 종류의 구성 요소가 Web Beans과 통합되어 Web Beans 서비스의 장점을 취하고 다른 종류의 Web Bean과 상호 작용합니다.
Web Beans는 Seam, Guice, Spring을 포함하여 다수의 기존 Java 프레임워크에 의해 영향을 받았지만 Web Beans은 자체적으로 다음과 같은 고유한 기능을 소유하고 있습니다: Seam 보다 더 타입 안정적, 보다 더 상태 기반적, Spring 보다 덜 XML-중심, Guice 보다 더 웹 및 엔터프라이즈-애플리케이션 사용 가능
보다 중요하게 Web Beans는 Java EE 및 내장 가능한 EJB Lite를 사용할 수 있는 Java SE 환경과 통합된 JCP 표준입니다.
첫 번째 Web Bean 작성을 시작해 보시겠습니까? 혹은 어떤 종류의 Web Beans 사양을 통해 도약하게 될 지를 의아해 하거나 의심하고 계실 수 도 있겠군요! 한 가지 좋은 정보는 여러분은 이미 수백개의 혹은 수천개의 Web Beans을 이미 작성 및 사용하고 계셨다는 것입니다. 아마 여러분은 처음으로 작성하신 Web Beans를 기억하지 못하고 계실 수 도 있습니다.
특정한 예외 상항에서 매개 변수가 없는 것을 허용하는 생성자와 함께하는 모든 Java 클래스는 Web Bean으로 이에는 모든 JavaBean이 포함됩니다. 이에 더하여 모든 EJB 3-스타일 세션 빈도 Web Bean입니다. 물론 매일 작성하셨던 JavaBeans 및 EJB는 Web Beans 사양에 의해 정의된 새로운 서비스의 장점을 취할 수 없지만, Web Beans으로서 기존 코드를 변경하지 않고 이 모든 것을 사용하실 수 있습니다 기타 다른 Web Beans로의 삽입, Web Beans XML 설정 기능을 통한 설정, 인터셉터 및 데코레이터 추가 등
다양한 애플리케이션에서 오랫동안 사용해 온 두 개의 Java 클래스를 갖고 있다고 가정합시다. 첫 번째 클래스는 문자열을 문장 목록으로 구문 분석합니다:
public class SentenceParser {
public List<String
> parse(String text) { ... }
}
두 번째 클래스는 하나의 언어에서 다른 언어로 문장을 번역할 수 있는 외부 시스템에 대한 무상태 세션 빈 프론트엔드입니다:
@Stateless
public class SentenceTranslator implements Translator {
public String translate(String sentence) { ... }
}
여기서 Translator
는 로컬 인터페이스입니다:
@Local
public interface Translator {
public String translate(String sentence);
}
불행하게도 전체 텍스트 문서를 번역하는 기존 클래스가 없으므로, 이러한 작업을 실행하는 Web Bean을 작성합시다:
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Initializer
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
}
public String translate(String text) {
StringBuilder sb = new StringBuilder();
for (String sentence: sentenceParser.parse(text)) {
sb.append(sentenceTranslator.translate(sentence));
}
return sb.toString();
}
}
인스턴스를 Web Bean, Servlet 또는 EJB로 삽입하여 TextTranslator
인스턴스를 얻을 수 있습니다:
@Initializer
public setTextTranslator(TextTranslator textTranslator) {
this.textTranslator = textTranslator;
}
다른 방법으로 Web Beans 관리자 방식을 직접 호출하여 인스턴스를 획득할 수 있습니다:
TextTranslator tt = manager.getInstanceByType(TextTranslator.class);
하지만 잠시 기다려주십시오: TextTranslator
는 매개 변수 없는 생성자를 갖지 않습니다! 그래도 이것이 Web Bean입니까? 클래스가 @Initializer
라고 어노테이션된 생성자를 갖고 있을 경우 매개 변수 없이 생성자를 갖지 않는 클래스는 Web Bean이 될 수 있습니다.
예상하셨듯이, @Initializer
어노테이션은 의존성 삽입을 사용하여 실행하기 위한 무엇인가를 갖고 있습니다! @Initializer
는 생성자 또는 Web Bean 방식에 적용될 수 있으며, Web Bean을 인스턴스화할 때 Web Bean 관리자에게 생성자 또는 Web Bean 방식을 호출할 것을 지시합니다. Web Bean 관리자는 기타 다른 Web Beans를 생성자 또는 방식의 매개 변수에 삽입하게 됩니다.
시스템 초기화시 Web Bean 관리자는 각각의 삽입 지점을 만족시키는 하나의 Web Bean이 존재하도록 이를 유효화해야 합니다. 예에서 사용 가능한 Translator
구현이 없을 경우 SentenceTranslator
EJB가 배치되지 않는 다면 Web Bean 관리자는 UnsatisfiedDependencyException
을 넘기게 됩니다. 하나 이상의 Translator
를 구현할 수 있을 경우, Web Bean 관리자는 AmbiguousDependencyException
을 넘기게 됩니다.
정확하게 Web Bean은 무엇인가요?
Web Bean은 비지니스 로직이 들어 있는 애플리케이션 클래스입니다. Web Bean은 Java 코드에서 직접 불러오거나 또는 Unified EL을 통해 불러올 수 있습니다. Web Bean은 트랜젝션 리소스에 액세스할 수 있습니다. Web Beans 사이에서의 종속성은 Web Bean 관리자에 의해 자동으로 관리됩니다. 대부분의 Web Beans은 상태 유지 (stateful) 및 컨텍스트 기반입니다. Web Bean 수명 주기는 항상 Web Bean 관리자에 의해 관리됩니다.
두 번째 내용으로 돌아가 봅시다. "컨텍스트화"된다는 의미는 정확하게 무엇입니까? Web Beans가 상태 유지 세션 빈이면, 보유하고 있는것이 어떤 빈 인스턴스인가가 문제입니다. 무상태 구성 요소 모델 이나 (예: 무상태 세션 빈) 또는 singleton 구성요소 모델 (예: ervlets 또는 singleton 빈)과는 다르게 Web Bean의 다른 클라이언트는 다른 상태에 있는 Web Bean을 보게 됩니다. 클라이언트-가시성 상태는 클라이언트가 참조하고 있는 Web Bean의 인스턴스가 무엇인가에 의존합니다.
하지만, 무상태 또는 싱글턴 모델과 같으나 상태 유지 세션 빈 과는 다르게, 클라이언트는 인스턴스의 수명 주기를 명시적으로 생성 또는 파괴하여 제어하지 못합니다. 대신, Web Bean의 범위는 다음 사항을 결정합니다:
각각의 Web Bean 인스턴스의 수명 주기
어떤 클라이언트가 특정 Web Bean 인스턴스의 참조를 공유할 것인지
Web Beans 애플리케이션에 있는 주어진 스레드의 경우, Web Bean 범위와 관련된 활성 컨텍스트가 있을 수 있습니다. 이러한 컨텍스트는 스레드에서 유일하거나 (예: 요청 범위일 경우) 또는 특정한 다른 스레드와 공유될 수 있거나 (예: Web Bean이 세션 범위일 경우) 또는 기타 다른 모든 스레드일 수 있습니다 (Web Bean이 애플리케이션 범위일 경우).
동일한 컨텍스트에서 실행되는 클라이언트 (예: 기타 다른 Web Bean)는 동일한 Web Bean의 인스턴스를 보게 됩니다. 하지만 다른 컨텍스트에서 실행되는 클라이언트는 다른 인스턴스를 보게 됩니다.
컨텍스트 모델의 큰 장점 중 하나는 상태 유지 Web Beans가 서비스처럼 다루어지게 하는 것입니다! 클라이언트는 사용되는 Web Bean의 수명 주기 관리 자체를 고려하거나, 또는 수명 주기가 무엇인지를 알 필요가 없습니다. Web Beans는 메세지를 전달하여 상호작용하고 Web Bean 구현은 자신의 상태에 따른 수명 주기를 정의합니다. Web Beans는 다음과 같은 이유로 느슨하게 연결되어 있습니다:
잘 정의된 공개 API를 통해 상호 작용하므로
수명 주기는 완전하게 연결 해제되므로
하나의 Web Bean을 동일한 API를 구현하고 다른 Web Bean 구현에 영향을 미치지 않고 다른 수명 주기 (다른 범위)를 갖는 다른 Web Bean으로 대체할 수 있습니다. 사실, 4.2절. “배치 유형 ”에서 살펴보실 수 있듯이 Web Beans는 배치시 Web Bean 구현을 덮어쓰기하기 위한 정교한 기능을 정의합니다.
모든 Web Bean 클라이언트가 Web Beans가 될 수 없음에 유의합니다. Servlets 또는 Message-Driven Beans와 같은 본래 삽입 가능한 컨텍스트 객체가 아닌 객체는 삽입에 의해 Web Beans에 참조를 획득할 수 있습니다.
보다 공식적으로 spec에 따르면:
Web Bean은 다음과 같은 것으로 구성되어 있습니다:
(비어 있지 않은) API 유형 모음
(비어 있지 않은) 바인딩 어노테이션 유형 모음
범위
배치 유형
Web Bean 이름 (옵션 사항)
인터셉터 바인딩 유형 모음
Web Bean 구현
이러한 용어가 Web Bean 개발자에게 무엇을 의미하는 살펴봅시다.
주로 Web Beans는 의존성 삽입을 통해 다른 Web Beans에 참조를 획득합니다. 삽입된 속성은 삽입될 Web Bean을 만족시키는 "계약"을 지정합니다. 계약에는 다음과 같은 내용을 지정합니다:
API 유형
바인딩 유형 모음
API는 사용자 정의 클래스 또는 인터페이스입니다. (Web Bean이 EJB 세션 빈일 경우, API 유형은 @Local
인터페이스이거나 또는 bean-class 로컬 보기입니다.) 바인딩 유형은 클라이언트-가시성 시멘틱을 나타내는 것으로 API의 일부 구현에 의해 만족됩니다.
바인딩 유형은 @BindingType
으로 어노테이션된 사용자 정의 어노테이션에 의해 나타납니다. 예를 들어, 다음과 같은 삽입 지점은 PaymentProcessor
API 유형 및 @CreditCard
바인딩 유형을 갖습니다:
@CreditCard PaymentProcessor paymentProcessor
바인딩 유형이 삽입 지점에 명확하게 지정되어 있지 않을 경우, 기본값 바인딩 유형@Current
가 사용됩니다.
각각의 삽입 지점의 경우, Web Bean 관리자는 계약을 만족시키는 (API를 구현하고 모든 바인딩 유형을 갖는) Web Bean을 검색하여 이를 삽입합니다.
다음과 같은 Web Bean은 @CreditCard
바인딩 유형을 갖고 PaymentProcessor
API 유형을 구현합니다. 따라서 이는 예시 삽입 지점에 삽입될 수 있습니다:
@CreditCard
public class CreditCardPaymentProcessor
implements PaymentProcessor { ... }
Web Bean이 바인딩 유형 모음을 명확히 지정하지 않을 경우, 이는 기본값 바인딩 유형인 @Current
라는 하나의 바인딩 유형을 갖습니다.
Web Beans는 정교하지만 직관적인 해상도 알고리즘을 정의하여 특정 계약을 만족시키는 하나 이상의 Web Bean이 있을 경우 컨테이너가 무엇을 해야할 지를 결정하는 것을 돕습니다. 보다 자세한 내용은 4장. 의존성 삽입 에서 다루겠습니다.
배치 유형은 배치 시나리오에 의해 Web Beans을 구분하게 합니다. 배치 유형은 특정 배치 시나리오를 나타네는 어노테이션으로, 예를 들어 @Mock
, @Staging
, @AustralianTaxLaw
가 있습니다. 시나리오에 배치되어야 할 Web Beans에 어노테이션을 적용합니다. 배치 유형은 단일 설정행을 사용하여 전체 Web Beans 모음이 상황에 따라 배치되게 합니다.
다수의 Web Beans는 배기본값 배치 유형 @Production
을 사용하므로, 이러한 경우 배치 유형을 명확하게 지정할 필요가 없습니다. 예에서 모든 Web Bean 트리는 @Production
배치 유형을 갖습니다.
테스트 환경에서, SentenceTranslator
Web Bean을 "모의 객체"로 교체하고자 합니다:
@Mock
public class MockSentenceTranslator implements Translator {
public String translate(String sentence) {
return "Lorem ipsum dolor sit amet";
}
}
MockSentenceTranslator
및 기타 다른 Web Bean 어노테이션 @Mock
을 사용해야 함을 나타내기 위해 테스트 환경에서 @Mock
배치 유형을 활성화할 수 있습니다.
4.2절. “배치 유형 ”에서 이러한 유일하고 강력한 기능에 관해 자세히 살펴 보겠습니다.
범위는 Web Bean의 수명 주기및 인스턴스의 가시성을 정의합니다. Web Beans 컨텍스트 모델은 확장 가능하고, 임의의 범위를 수용합니다. 하지만, 특정 중요 범위는 사양으로 내장되어 있으며, Web Bean 관리자가 제공합니다. 범위는 어노테이션 유형에 의해 나타납니다.
예를 들어, 웹 애플리케어션은 세션 범위 Web Beans을 갖을 수 있습니다:
@SessionScoped
public class ShoppingCart { ... }
세션 범위 Web Bean의 인스턴스는 사용자 세션으로 바운딩되어 세션 컨텍스트에서 실행되는 모든 요청에 의해 공유됩니다.
기본값으로, Web Beans는 dependent pseudo-scope라는 특정 범위에 속합니다. 이러한 범위를 갖는 Web Beans는 삽입되어야할 객체의 순수한 의존적 객체이며 수명주기는 객체의 수명주기로 바운딩됩니다.
5장. 범위 및 컨텍스트 에서 범위에 대해 보다 자세하게 다루겠습니다.
Web Bean은 이름을 갖을 수 있으며, Unified EL 표현식에서 사용될 수 있습니다. Web Bean의 이름을 지정하는 것은 쉽습니다:
@SessionScoped @Named("cart")
public class ShoppingCart { ... }
이제 JSF 또는 JSP 페이지에서 쉽게 Web Bean을 사용할 수 있습니다:
<h:dataTable value="#{cart.lineItems}" var="item"> .... </h:dataTable >
Web Bean 관리자기 이름을 기본값으로 하게 하는 것이 보다 수월합니다:
@SessionScoped @Named
public class ShoppingCart { ... }
이러한 경우, 이름 기본값은 shoppingCart
가 됩니다 첫번째 문자가 소문자로 된 수식어가 붙지않는 클래스 이름.
Web Beans는 EJB beans 뿐 만 아니라 일반 Java 클래스에 대해 EJB 3에 의해 정의된 인터셉터 기능을 지원합니다. 이에 더하여, Web Beans는 바인딩 인터셉터, EJB beans 및 기타 다른 Web Beans에 새로운 접근 방식을 제공합니다.
@Interceptors
어노테이션의 사용을 통해 인터셉터 클래스를 직접 지정할 수 있습니다:
@SessionScoped
@Interceptors(TransactionInterceptor.class)
public class ShoppingCart { ... }
하지만, 인터셉터 바인딩 유형을 통해 인터셉터 바인딩을 돌려 놓는 것이 보다 좋습니다:
@SessionScoped @Transactional
public class ShoppingCart { ... }
JavaBeans, EJB 및 기타 다른 Java 클래스가 Web Beans이 될 수 있음을 살펴보았습니다. 하지만, 정확히 어떤 종류의 객체가 Web Beans인가요?
Web Beans 사양은 다음과 같을 경우 구체적 Java 클래스가 심플 Web Bean이라고 말합니다:
EJB, Servlet 또는 JPA 엔티티와 같이 EE 컨테이너 관리 기반 구성요소가 아닐 경우,
비-정적인 내부 클래스가 아닐 경우,
매개 변수화된 유형이 아닐 경우,
매개 변수 없는 생성자나 또는 @Initializer
어노테이션된 생성자를 갖을 경우,
따라서, 거의 모든 JavaBean은 심플 Web Bean이 됩니다.
심플 Web Bean에 의해 직접적 또는 간접적으로 구현되는 모든 인터페이스는 API 유형의 심플 Web Bean입니다. 클래스 및 상위클래스도 API 유형이 됩니다.
사양에서는 모든 EJB 3 스타일 세션 및 singleton beans가 EJB 3 엔터프라이즈 Web Beans라고 말합니다. Message driven beans는 Web Beans이 아닙니다 다른 객체에 삽입되도록 되어있지 않기 때문 하지만 이는 의존성 삽입 및 인터셉터를 포함한 대부분의 Web Beans 기능의 장점을 취할 수 있습니다.
와일드카드 유형 매개 변수 또는 유형 변수를 갖지 않는 엔터프라이즈 Web Bean의 모든 로컬 인터페이스 및 이의 상위인터페이스는 엔터프라이즈 Web Bean의 API 유형입니다. EJB bean이 bean 클래스 로컬 보기를 갖고 있을 경우 bean 클래스 및 이의 모든 상위 클래스도 API 유형입니다.
상태유지 세션 빈은 매개 변수가 없는 제거 방식이나 @Destructor
로 어노테이션된 삭제 방식을 명시해야 합니다. Web Bean 관리자는 수명 주기의 마지막에 상태 유지 세션 빈 인스턴스를 파괴하기 위해 이러한 방식을 호출합니다. 이러한 방식은 엔터프라이즈 Web Bean의 파괴자 방식이라고 합니다.
@Stateful @SessionScoped
public class ShoppingCart {
...
@Remove
public void destroy() {}
}
그러면 언제 심플 Web Bean 대신 엔터프라이즈 Web Bean을 사용해야 할까요? 다음과 같이 EJB에 의해 제공되는 고급 엔터프라이즈 서비스가 필요할 때 마다 사용하면 됩니다:
메소드-수준 트랜젝션 관리 및 보안
동시성 관리
상태 유지 세션 빈 용 인스턴스 레벨 수동화 및 무상태 세션 빈 용 인스턴스 풀링
원격 및 웹 서비스 호출
타이머 및 비동기 방식
엔터프라이즈 Web Bean을 사용해야 합니다. 이러한 것이 전혀 필요하지 않을 경우, 심플 Web Bean도 잘 실행될 것입니다.
다수의 Web Beans (세션 또는 애플리케이션 범위 Web Bean 포함)은 동시 액세스에서 사용 가능합니다. 따라서, EJB 3.1에 의해 제공되는 동시성 관리는 아주 유용합니다. 대부분의 세션 및 애플리케이션 범위 Web Beans는 EJB이어야 합니다.
Web Beans는 중량의 리소스에 참조를 보유하고 있거나 EJB @Stateless
/@Stateful
/@Singleton
모델에 의해 정의된 고급 컨테이너 관리 수명주기로 부터의 내부적 상태 장점을 수동화 및 인스턴스 풀링 지원과 함께 보유하고 있어야 합니다.
마지막으로, 메서드-수준 트랜젝션 관리, 메서드-수준 보안, 타이머, 원격 방식 또는 비동기 방식은 명백하게 필요합니다.
심플 Web Bean으로 시작하고, @Stateless
, @Stateful
, @Singleton
어노테이션을 추가하여 EJB로 변환합니다.
생산자 방식은 현재 컨텍스트에 인스턴스가 존재하지 않을 때 Web Bean의 인스턴스를 획득하기 위해 Web Bean 관리자에 의해 호출되는 방식입니다. 생산자 방식은 인스턴스를 Web Bean 관리자가 관리하게 두지 않고 애플리케이션이 인스턴스 절차를 완전히 제어하게 합니다. 예:
@ApplicationScoped
public class Generator {
private Random random = new Random( System.currentTimeMillis() );
@Produces @Random int next() {
return random.nextInt(100);
}
}
생산자 방식 결과는 기타 다른 Web Bean과 같이 삽입됩니다.
@Random int randomNumber
방식 반환 유형 및 직접적이나 간접적으로 확장/구현하는 모든 인터페이스 API 유형의 생산자 방식입니다. 반환 유형이 클래스일 경우 모든 상위클래스도 API 유형이 됩니다.
일부 생산자 방식은 명시적 파괴를 요청하는 객체를 반환합니다:
@Produces @RequestScoped Connection connect(User user) {
return createConnection( user.getId(), user.getPassword() );
}
이러한 생산자 방식은 폐지 방식과 일치하게 정의될 수 있습니다:
void close(@Disposes Connection connection) {
connection.close();
}
이러한 폐지 방식은 요청 마지막에 Web Bean 관리자에 의해 자동으로 호출됩니다.
6장. 생산자 방식 에서 생산자 방식에 관해 보다 자세하게 다룹니다.
마지막으로, JMS 큐 또는 토픽은 Web Bean이 될 수 있습니다. Web Beans는 큐 및 토픽에 메세지를 전달하기 위해 필요한 모든 다양한 JMS 객체의 수명주기 관리에 있어서 개발자에게 단조로움을 완화시킵니다. 13.4절. “JMS 엔드포인트 ”에서 JMS 엔드포인트를 다루게 됩니다.
이러한 웹 애플리케이션의 예를 살펴봅시다. JSF를 사용하는 애플리케이션의 사용자 로그인/로그아웃을 구현할 것입니다. 먼저, 로그인시 입력한 사용자 이름 및 암호를 보유하기 위해 Web Bean을 정의합니다:
@Named @RequestScoped
public class Credentials {
private String username;
private String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
Web Bean은 다음과 같은 JSF 형식에서 로그인 프롬프트로 바운딩됩니다:
<h:form>
<h:panelGrid columns="2" rendered="#{!login.loggedIn}">
<h:outputLabel for="username"
>Username:</h:outputLabel>
<h:inputText id="username" value="#{credentials.username}"/>
<h:outputLabel for="password"
>Password:</h:outputLabel>
<h:inputText id="password" value="#{credentials.password}"/>
</h:panelGrid>
<h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/>
<h:commandButton value="Logout" acion="#{login.logout}" rendered="#{login.loggedIn}"/>
</h:form
>
현재 로그인 사용자에 관한 정보를 관리하는 Web Bean 세션 범위에 의해 실제 작업이 완료되어 다른 Web Beans에 User
엔티티를 노출시킵니다:
@SessionScoped @Named
public class Login {
@Current Credentials credentials;
@PersistenceContext EntityManager userDatabase;
private User user;
public void login() {
List<User
> results = userDatabase.createQuery(
"select u from User u where u.username=:username and u.password=:password")
.setParameter("username", credentials.getUsername())
.setParameter("password", credentials.getPassword())
.getResultList();
if ( !results.isEmpty() ) {
user = results.get(0);
}
}
public void logout() {
user = null;
}
public boolean isLoggedIn() {
return user!=null;
}
@Produces @LoggedIn User getCurrentUser() {
return user;
}
}
@LoggedIn
은 바인딩 어노테이션입니다:
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD})
@BindingType
public @interface LoggedIn {}
기타 다른 Web Bean은 현재 사용자를 쉽게 삽입할 수 있습니다:
public class DocumentEditor {
@Current Document document;
@LoggedIn User currentUser;
@PersistenceContext EntityManager docDatabase;
public void save() {
document.setCreatedBy(currentUser);
docDatabase.persist(document);
}
}
이러한 예가 Web Bean 프로그래밍 모델의 맛을 보는 계기가 되었으면 합니다. 다음 부분에서는 Web Beans 의존성 삽입에 대해 자세히 살펴보겠습니다.
The Web Beans is being developed at the Seam project. You can download the latest developer release of Web Beans from the the downloads page.
Web Beans comes with a two deployable example applications: webbeans-numberguess
, a war example, containing only simple beans, and webbeans-translator
an ear example, containing enterprise beans. There are also two variations on the numberguess example, the tomcat example (suitable for deployment to Tomcat) and the jsf2 example, which you can use if you are running JSF2. To run the examples you'll need the following:
the latest release of Web Beans,
JBoss AS 5.0.1.GA, or
Apache Tomcat 6.0.x, and
Ant 1.7.0.
You'll need to download JBoss AS 5.0.1.GA from jboss.org, and unzip it. For example:
$ cd /Applications $ unzip ~/jboss-5.0.1.GA.zip
Next, download Web Beans from seamframework.org, and unzip it. For example
$ cd ~/ $ unzip ~/webbeans-$VERSION.zip
다음으로, JBoss가 위치해 있는 곳을 Web Beans에게 알려야 합니다. jboss-as/build.properties
를 편집하고 jboss.home
속성을 설정합니다. 예:
jboss.home=/Applications/jboss-5.0.1.GA
To install Web Beans, you'll need Ant 1.7.0 installed, and the ANT_HOME
environment variable set. For example:
$ unzip apache-ant-1.7.0.zip $ export ANT_HOME=~/apache-ant-1.7.0
Then, you can install the update. The update script will use Maven to download Web Beans automatically.
$ cd webbeans-$VERSION/jboss-as $ ant update
이제, 첫번째 예제를 배치할 준비가 되었습니다!
The build scripts for the examples offer a number of targets for JBoss AS, these are:
ant restart
- exploded 형식으로 예제를 배치합니다
ant explode
- 배치 버전을 다시 시작하지 않고 exploded 예제를 업데이트합니다
ant deploy
- 압축된 jar 포맷으로 예제를 배치합니다
ant undeploy
- 서버에서 예제를 제거합니다
ant clean
- 예제를 지웁니다
numberguess 예제를 배치하려면:
$ cd examples/numberguess ant deploy
Start JBoss AS:
$ /Application/jboss-5.0.0.GA/bin/run.sh
If you use Windows, use the run.bat
script.
애플리케이션이 배치되면 http://localhost:8080/webbeans-numberguess에서 살펴보시기 바랍니다!
Web Beans includes a second simple example that will translate your text into Latin. The numberguess example is a war example, and uses only simple beans; the translator example is an ear example, and includes enterprise beans, packaged in an EJB module. To try it out:
$ cd examples/translator ant deploy
애플리케이션이 배치되면 http://localhost:8080/webbeans-translator에 가보십시오!
You'll need to download Tomcat 6.0.18 or later from tomcat.apache.org, and unzip it. For example:
$ cd /Applications $ unzip ~/apache-tomcat-6.0.18.zip
Next, download Web Beans from seamframework.org, and unzip it. For example
$ cd ~/ $ unzip ~/webbeans-$VERSION.zip
Next, we need to tell Web Beans where Tomcat is located. Edit jboss-as/build.properties
and set the tomcat.home
property. For example:
tomcat.home=/Applications/apache-tomcat-6.0.18
The build scripts for the examples offer a number of targets for Tomcat, these are:
ant tomcat.restart
- deploy the example in exploded format
ant tomcat.explode
- update an exploded example, without restarting the deployment
ant tomcat.deploy
- deploy the example in compressed jar format
ant tomcat.undeploy
- remove the example from the server
ant tomcat.clean
- clean the example
To deploy the numberguess example for tomcat:
$ cd examples/tomcat ant tomcat.deploy
Start Tomcat:
$ /Applications/apache-tomcat-6.0.18/bin/startup.sh
If you use Windows, use the startup.bat
script.
애플리케이션이 배치되면 http://localhost:8080/webbeans-numberguess에서 살펴보시기 바랍니다!
numberguess 애플리케이션에서 1에서 100사이의 숫자를 알아내기 위해 주어진 10 번을 시도하게 됩니다. 각각 시도한 후 숫자가 너무 높은지 또는 너무 낮은지를 알려주게 됩니다.
numberguess 예제는 여러 Web Beans, 설정 파일, Facelet JSF 페이지로 구성되어 있으며, war로 패키지되어 있습니다 설정 파일부터 시작합시다.
예제에 해당하는 모든 설정 파일은 WEB-INF/
에 위치해 있으며, 이는 소스 트리에 있는 WebContent
에 저장되어 있습니다. 먼저, faces-config.xml
을 사용하여, Facelets를 사용할 JSF를 알려주게 됩니다:
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="1.2"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<application>
<view-handler
>com.sun.facelets.FaceletViewHandler</view-handler>
</application>
</faces-config
>
여기에는 빈 web-beans.xml
파일이 있어, 이는 Web Beans 애플리케이션으로 애플리케이션을 표시합니다.
마지막으로, web.xml
파일이 있습니다:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name >Web Beans Numbergues example</display-name> <!-- JSF --><servlet> <servlet-name >Faces Servlet</servlet-name> <servlet-class >javax.faces.webapp.FacesServlet</servlet-class> <load-on
-startup >1</load-on-startup> </servlet> <servlet-mapping> <servlet
-name >Faces Servlet</servlet-name> <url-pattern >*.jsf</url-pattern> </servlet-mapping>
<context-param> <param-name >javax.faces.DEFAULT_SUFFIX</param-name> <param-v
alue >.xhtml</param-value> </context-param> <session-config> <session-timeout >10</session-timeout> </session-config> </web-app >
![]() | Enable and load the JSF servlet |
![]() | Configure requests to |
![]() | Tell JSF that we will be giving our source files (facelets) an extension of |
![]() | Configure a session timeout of 10 minutes |
Whilst this demo is a JSF demo, you can use Web Beans with any Servlet based web framework.
Let's take a look at the Facelet view:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:s="http://jboss.com/products/seam/taglib"> <ui:composition template="template.xhtml"> <ui:define name="content"> <h1 >Guess a number...</h1> <h:form
id="NumberGuessMain"> <div style="color: red"> <h:messages id="messages" globalOnly="false"/> <h:outputText id="Higher" value="Higher!" rendered="#{game.number gt game.guess and game.guess ne 0}"/> <h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess and game.guess ne 0}"/> </div> <div
> I'm thinking of a number between #{game.smallest} and #{game.biggest}. You have #{game.remainingGuesses} guesses. </div> <div> Y
our guess: <h:inputText id="inputGuess" value="#{game.guess}" required="true" size="3"
disabled="#{game.number eq game.guess}"> <f:validateLongRange maximum="#{game.biggest}" minimum="#{game.smallest}"/> <
/h:inputText> <h:commandButton id="GuessButton" value="Guess" action="#{game.check}" disabled="#{game.number eq game.guess}"/> </div> <div> <h:commandButton id="RestartButton" value="Reset" action="#{game.reset}" immediate="true" /> </div> </h:form> </ui:define> </ui:composition> </html >
![]() | Facelets is a templating language for JSF, here we are wrapping our page in a template which defines the header. |
![]() | There are a number of messages which can be sent to the user, "Higher!", "Lower!" and "Correct!" |
![]() | As the user guesses, the range of numbers they can guess gets smaller - this sentance changes to make sure they know what range to guess in. |
![]() | This input field is bound to a Web Bean, using the value expression. |
![]() | A range validator is used to make sure the user doesn't accidentally input a number outside of the range in which they can guess - if the validator wasn't here, the user might use up a guess on an out of range number. |
![]() | And, of course, there must be a way for the user to send their guess to the server. Here we bind to an action method on the Web Bean. |
예제에는 4 개의 클래스가 존재합니다, 첫 번째 두 개는 바인딩 유형입니다. 먼저, 임의의 숫자를 삽입하기 위해 사용되는 @Random
바인딩 유형이 있습니다:
@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@BindingType
public @interface Random {}
삽입될 수 있는 최대 번호 삽입하기 위해 사용되는 @MaxNumber
바인딩 유형도 있습니다:
@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@BindingType
public @interface MaxNumber {}
Generator
클래스는 생산자 방식을 통해 임의의 숫자를 생성해야 할 책임이 있습니다. 또한 이는 생산자 방식을 통하여 가능한 최대 숫자를 나타냅니다:
@ApplicationScoped
public class Generator {
private java.util.Random random = new java.util.Random( System.currentTimeMillis() );
private int maxNumber = 100;
java.util.Random getRandom()
{
return random;
}
@Produces @Random int next() {
return getRandom().nextInt(maxNumber);
}
@Produces @MaxNumber int getMaxNumber()
{
return maxNumber;
}
}
Generator
는 애플리케이션 범위로 되어 있음을 발견하실 것입니다; 따라서 매번 다른 임의 숫자를 갖지 않게 됩니다.
애플리케이션에 있는 마지막 Web Bean은 Game
범위 세션입니다.
@Named
어노테이션이 사용되므로 JSF 페이지에서 EL을 통해 bean을 사용할 수 있음을 인지하실 것입니다. 마지막으로 생성자 삽입을 사용하여 임의의 숫자로 게임을 초기화합니다. 물론, 게임 플레이어에게 언제 게임에어 이겼는지를 알려주어야 하므로, FacesMessage
로 피드백을 제공합니다.
package org.jboss.webbeans.examples.numberguess;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.webbeans.AnnotationLiteral;
import javax.webbeans.Current;
import javax.webbeans.Initializer;
import javax.webbeans.Named;
import javax.webbeans.SessionScoped;
import javax.webbeans.manager.Manager;
@Named
@SessionScoped
public class Game
{
private int number;
private int guess;
private int smallest;
private int biggest;
private int remainingGuesses;
@Current Manager manager;
public Game()
{
}
@Initializer
Game(@MaxNumber int maxNumber)
{
this.biggest = maxNumber;
}
public int getNumber()
{
return number;
}
public int getGuess()
{
return guess;
}
public void setGuess(int guess)
{
this.guess = guess;
}
public int getSmallest()
{
return smallest;
}
public int getBiggest()
{
return biggest;
}
public int getRemainingGuesses()
{
return remainingGuesses;
}
public String check()
{
if (guess
>number)
{
biggest = guess - 1;
}
if (guess<number)
{
smallest = guess + 1;
}
if (guess == number)
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
}
remainingGuesses--;
return null;
}
@PostConstruct
public void reset()
{
this.smallest = 0;
this.guess = 0;
this.remainingGuesses = 10;
this.number = manager.getInstanceByType(Integer.class, new AnnotationLiteral<Random
>(){});
}
}
The numberguess for Tomcat differs in a couple of ways. Firstly, Web Beans should be deployed as a Web Application library in WEB-INF/lib
. For your convenience we provide a single jar suitable for running Web Beans on Tomcat webbeans-tomcat.jar
.
Of course, you must also include JSF and EL, as well common annotations (jsr250-api.jar
) which a JEE server includes by default.
Secondly, we need to explicitly specify the Tomcat servlet listener (used to boot Web Beans, and control it's interaction with requests) in web.xml
:
<listener> <listener-class>org.jboss.webbeans.environment.tomcat.Listener</listener-class> </listener>
번역 예제는 입력하신 아무 문장을 가져가 이를 라틴어로 번역합니다.
번역 예제는 ear로 작성되며, EJB가 들어있게 됩니다. 따라서, 문장 구조가 numberguess 예보다 훨씬 복잡합니다.
EJB 3.1 및 Jave EE 6는 EJB를 war로 패키지하게 하여, 이러한 문장을 보다 간단하게 만들게 됩니다!
먼저, webbeans-translator-ear
모듈에 있는 ear aggregator를 살펴봅시다. Maven은 자동으로 application.xml
을 생성합니다:
<plugin>
<groupId
>org.apache.maven.plugins</groupId>
<artifactId
>maven-ear-plugin</artifactId>
<configuration>
<modules>
<webModule>
<groupId
>org.jboss.webbeans.examples.translator</groupId>
<artifactId
>webbeans-translator-war</artifactId>
<contextRoot
>/webbeans-translator</contextRoot>
</webModule>
</modules>
</configuration>
</plugin
>
url (http://localhost:8080/webbeans-translator)을 제공하는 컨텍스트 경로를 설정합니다.
Maven을 사용하여 이러한 파일을 생성할 경우, META-INF/application.xml
이 필요합니다:
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd"
version="5">
<display-name
>webbeans-translator-ear</display-name>
<description
>Ear Example for the reference implementation of JSR 299: Web Beans</description>
<module>
<web>
<web-uri
>webbeans-translator.war</web-uri>
<context-root
>/webbeans-translator</context-root>
</web>
</module>
<module>
<ejb
>webbeans-translator.jar</ejb>
</module>
</application
>
Next, lets look at the war. Just as in the numberguess example, we have a faces-config.xml
(to enable Facelets) and a web.xml
(to enable JSF) in WebContent/WEB-INF
.
텍스트를 번역하데 facelet이 사용됩니다. numberguess 예제에서와 같이 양식으로된 템플릿이 있습니다 (간결하게 하기 위해 여기서는 생략됨):
<h:form id="NumberGuessMain">
<table>
<tr align="center" style="font-weight: bold" >
<td>
Your text
</td>
<td>
Translation
</td>
</tr>
<tr>
<td>
<h:inputTextarea id="text" value="#{translator.text}" required="true" rows="5" cols="80" />
</td>
<td>
<h:outputText value="#{translator.translatedText}" />
</td>
</tr>
</table>
<div>
<h:commandButton id="button" value="Translate" action="#{translator.translate}"/>
</div>
</h:form
>
사용자는 왼쪽 텍스트 부분에 텍스트를 입력할 수 있으며, 번역하기 버튼을 누르면 오른쪽에 번역 결과가 나타나게 됩니다.
마지막으로, ejb 모듈인 webbeans-translator-ejb
를 살펴봅시다. src/main/resources/META-INF
에는 Web Beans가 들어 있는 것으로 아카이브를 표시하기 위해 사용되는 빈 web-beans.xml
이 있습니다.
가장 흥미로운 코드 부분은 마지막을 위해 남겨두겠습니다! 프로젝트에는 두 개의 심플 beans인 SentenceParser
및 TextTranslator
와 두 개의 엔터프라이즈 beans인 TranslatorControllerBean
및 SentenceTranslator
가 있습니다. 이제 Web Bean에 관해 보다 많이 알고 계실 것이므로, 가장 중요한 부분만 여기서 다루겠습니다.
SentenceParser
및 TextTranslator
는 beans에 의존하며, TextTranslator
는 생성자 초기화를 사용합니다:
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Initializer
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator)
{
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
TextTranslator
는 무상태 세션빈으로 (로컬 비지니스 인터페이스와 함께), 완전한 번역기를 개발할 수는 없지만, 잘 작동하고 있습니다!
마지막으로, UI 기반 제어기가 있어, 이는 사용자로 부터 텍스트를 수집하여 번역기에 이를 보냅니다. 이는 요청 범위, 이름, 상태 유지 세션빈으로 번역기에 삽입되어 있습니다.
@Stateful
@RequestScoped
@Named("translator")
public class TranslatorControllerBean implements TranslatorController
{
@Current TextTranslator translator;
bean은 페이지에 있는 모든 영역에 대해 getter 및 setter를 갖습니다.
이는 상태 유지 세션 빈이므로, 제거 방식을 갖고 있어야 합니다:
@Remove
public void remove()
{
}
Web Beans 관리자는 bean이 삭제될 때 제거 방식을 호출하게 됩니다; 이러한 경우 요청 마지막에 호출하게 됩니다.
That concludes our short tour of the Web Beans examples. For more on Web Beans , or to help out, please visit http://www.seamframework.org/WebBeans/Development.
버그 수정, 새로운 기능 작성, 예세 작성, 참조 가이드 번역과 같이 모든 영역에서 도움이 필요합니다.
Web Beans는 의존성 삽입에 대한 세 가지 주요 메카니즘을 지원합니다:
생성자 매개 변수 삽입:
public class Checkout {
private final ShoppingCart cart;
@Initializer
public Checkout(ShoppingCart cart) {
this.cart = cart;
}
}
초기화 방식 매개 변수 삽입:
public class Checkout {
private ShoppingCart cart;
@Initializer
void setShoppingCart(ShoppingCart cart) {
this.cart = cart;
}
}
직접적 영역 삽입:
public class Checkout {
private @Current ShoppingCart cart;
}
Web Bean 인스턴스가 먼저 인스턴스화되었을 경우 의존성 삽입이 발생합니다.
먼저, Web Bean 관리자는 Web Bean 생성자를 호출하여 Web Bean 인스턴스를 획득합니다.
다음으로, Web Bean 관리자는 Web Bean의 삽입된 모든 영역의 값을 초기화합니다.
그 후, Web Bean 관리자는 Web Bean의 모든 초기화 방식을 호출합니다.
마지막으로 Web Bean의 @PostConstruct
방식이 호출됩니다.
EJB가 Web Bean 관리자가 아닌 EJB 컨테이너에 의해 인스턴스화된 이래 생성자 매개변수 삽입은 EJB beans을 지원하지 않습니다.
기본값 바인딩 유형 @Current
가 적용되었을 경우 생성자의 매개 변수 및 초기화 방식에서는 명시적으로 어노테이션할 필요가 없습니다. 하지만 삽입된 영역에는 반드시 바인딩 유형을 지정해야 하며, 언제 기본값 바인딩 유형을 적용할 지도 지정해야 합니다. 영역에 바인딩 유형이 지정되어 있지 않을 경우, 이는 삽입되지 않게 됩니다.
생산자 방식은 매개 변수 삽입을 지원합니다:
@Produces Checkout createCheckout(ShoppingCart cart) {
return new Checkout(cart);
}
마지막으로 옵저버 방식 (9장. 이벤트 에서 살펴보게됨), 폐지 방식 및 소멸자 방식 모두는 매개 변수 삽입을 지원합니다.
Web Beans 사양은 타입 안정적 해상도 알고리즘이라는 절차를 정의하여, Web Bean 관리자가 삽입 지점에 삽입하기 위해 Web Bean을 인식할 때 이를 따르게 됩니다. 이러한 알고르짐은 처음에는 복잡하게 보이지만, 일단 이를 이해하면, 이는 다소 직관적입니다. 타입 안정적 해상도는 시스템 초기화시에 실행되어, 관리자는 사용자에 과한 정보를 즉각적으로 알게되며 Web Bean의 의존성에 만족하지 않을 경우, UnsatisfiedDependencyException
또는 AmbiguousDependencyException
을 넘기게 됩니다.
이러한 알고리즘은 여러 Web Beans를 허용하여 동일한 API 유형을 구현하기 위한 것입니다:
또는 클라이언트가 바인딩 어노테이션을 사용하여 필요한 구현 사항을 선택하게 합니다,
애플리케이션 개발자가 클라이언트로 변경하지 않고 배치 유형을 활성화 또는 비활성화하여 특정 시스템에 어떤 구헌이 적합할 지를 선택하게 합니다.
하나의 API 구현이 클라이언트에 변경하지 않고 배치 유형 우선 순위를 사용하여 배치시 다른 동일한 API 구현을 덮어쓰기하게 합니다.
Web Beans 관리자가 어떻게 Web Bean을 삽입할 지를 결정하는 방법에 대해 살펴봅시다.
특정 API 유형을 구현하는 하나 이상의 Web Bean이 있을 경우, 삽입 지점은 바인딩 어노테이션을 사용하여 어떤 Web Bean이 삽입되어야 할 지를 지정할 수 있습니다. 예를 들어, PaymentProcessor
의 두 가지 구현이 있을 수 있습니다:
@PayByCheque
public class ChequePaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
@PayByCreditCard
public class CreditCardPaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
여기서 @PayByCheque
및 @PayByCreditCard
는 바인딩 어노테이션입니다:
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
@BindingType
public @interface PayByCheque {}
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
@BindingType
public @interface PayByCreditCard {}
클라이언트 Web Bean 개발자는 바인딩 어노테이션을 사용하여 정확히 어떤 Web Bean이 삽입되어야 하는 지를 지정합니다.
영역 삽입 사용:
@PayByCheque PaymentProcessor chequePaymentProcessor;
@PayByCreditCard PaymentProcessor creditCardPaymentProcessor;
초기화 방식 삽입 사용:
@Initializer
public void setPaymentProcessors(@PayByCheque PaymentProcessor chequePaymentProcessor,
@PayByCreditCard PaymentProcessor creditCardPaymentProcessor) {
this.chequePaymentProcessor = chequePaymentProcessor;
this.creditCardPaymentProcessor = creditCardPaymentProcessor;
}
생성자 삽입 사용:
@Initializer
public Checkout(@PayByCheque PaymentProcessor chequePaymentProcessor,
@PayByCreditCard PaymentProcessor creditCardPaymentProcessor) {
this.chequePaymentProcessor = chequePaymentProcessor;
this.creditCardPaymentProcessor = creditCardPaymentProcessor;
}
바인딩 어노테이션은 멤버를 갖을 수 있습니다:
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
@BindingType
public @interface PayBy {
PaymentType value();
}
이러한 경우, 멤버 값이 중요합니다:
@PayBy(CHEQUE) PaymentProcessor chequePaymentProcessor;
@PayBy(CREDIT_CARD) PaymentProcessor creditCardPaymentProcessor;
Web Bean 관리자에게 @NonBinding
멤버를 어노테이션하여 바인딩 어노테이션 유형 멤버를 무시하라고 말할 수 있습니다.
삽입 지점은 여러 바인딩 어노테이션을 지정할 수 도 있습니다:
@Asynchronous @PayByCheque PaymentProcessor paymentProcessor
이러한 경우, 양쪽 바인딩 어노테이션을 갖는 Web Bean만 삽입될 수 있습니다.
생산자 방식은 바인딩 어노테이션을 지정할 수 도 있습니다:
@Produces
@Asynchronous @PayByCheque
PaymentProcessor createAsyncPaymentProcessor(@PayByCheque PaymentProcessor processor) {
return new AsynchronousPaymentProcessor(processor);
}
모든 Web Beans는 배치 유형을 갖습니다. 각각의 배치 유형은 시스템의 일부 배치에 조건부로 설치되어야 하는 Web Beans 모음을 인식합니다.
예를 들어, @Mock
라는 배치 유형을 정의할 수 있으며, 이는 시스템이 통합적인 테스트 환경 내에서 실행될 때 설치되어야 하는 Web Beans를 인식합니다:
@Retention(RUNTIME)
@Target({TYPE, METHOD})
@DeploymentType
public @interface Mock {}
지불 절차를 처리하기 위한 외부적 시스템과 상호 작용하는 일부 Web Bean이 있다고 가정합시다:
public class ExternalPaymentProcessor {
public void process(Payment p) {
...
}
}
이러한 Web Bean이 배치 유형을 명시적을 지정하지 않고 있으므로, 이는 기본값 배치 유형 @Production
을 갖게 됩니다.
통합 또는 단위 테스트를 위해 외부적 시스템은 속도가 느리거나 또는 사용 불가능합니다. 따라서 모의 객체를 생성할 수 있습니다:
@Mock
public class MockPaymentProcessor implements PaymentProcessor {
@Override
public void process(Payment p) {
p.setSuccessful(true);
}
}
하지만 Web Bean 관리자가 특정 배치에 어떤 구현을 사용할 지를 어떻게 결정할까요?
Web Beans는 두 개의 내장된 배치 유형을 정의합니다: @Production
및 @Standard
. 시스템이 배치되면 기본값으로 내장된 배치 유형과 함께 Web Beans 만이 활성화됩니다. web-beans.xml
에서 목록을 나열하여 특정 배치에서 활성화될 추가 배치 유형을 인식할 수 있습니다.
예제로 다시 돌아가서, 통합적 테스트를 배치할 때, 모든 @Mock
객체가 설치되기를 원합니다:
<WebBeans>
<Deploy>
<Standard/>
<Production/>
<test:Mock/>
</Deploy>
</WebBeans
>
이제 Web Bean 관리자는 배치시 @Production
, @Standard
, @Mock
어노테이션된 모든 Web Beans를 인식 및 설치하게 됩니다.
@Standard
배치 유형은 Web Beans 사양에 의해 정의된 특정 Web Beans에서만 사용됩니다. 자체적 Web Beans에는 이를 사용할 수 없으며 이를 비활성화할 수 없습니다.
@Production
배치 유형은 배치 유형을 명시하지 않은 Web Beans에 대한 기본값 배치 유형으로 비활성화될 수 있습니다.
관심을 기울이셨다면, Web Bean 관리자가 어떤 구현 ExternalPaymentProcessor
또는 MockPaymentProcessor
을 선택할 지를 어떻게 결정하는지에 대해 궁금해 하셨을 것입니다. 관리자기 이러한 삽입 지점에 이르렀을 때 무엇이 발생할 지를 고려합니다:
@Current PaymentProcessor paymentProcessor
PaymentProcessor
계약을 만족하는 두 개의 Web Beans가 있습니다. 삽입 지점에서 바인딩 어노테이션은 소스로 하드-코드화되어 있으므로, 명확하게 하기 위해 바인딩 어노테이션을 사용할 수 없으며, 관리자가 배치시 결정할 수 있게 하기를 원합니다!
이러한 문제의 해결책은 각각의 배치 유형이 다른 우선 순위를 갖게 하는 것입니다. 배치 유형의 우선 순위는 web-beans.xml
에 나타나는 순서에 의해 결정됩니다. 예에서 @Mock
는 @Production
보다 나중에 나타나므로 보다 높은 우선 순위를 갖습니다.
하나 이상의 Web Bean이 삽입 지점에 의해 지정된 계약 (API 유형 및 바인딩 어노테이션)에 만족할 수 있음을 관리자가 발견할 때 마다, 이는 Web Beans의 관련된 우선 순위를 고려합니다. 하나의 Web Bean이 다른 것 보다 높은 우선 순위를 갖을 경우, 삽입될 보다 높은 우선 순위의 Web Bean을 선택합니다. 예에서, 통합 테스트 환경 (실제적으로 원하는 환경)에서 실행할 때 Web Bean 관리자는 MockPaymentProcessor
를 삽입하게 됩니다.
이러한 기능을 오늘날의 관리자 구조와 비교하는 것은 흥미로운 일입니다. 다양한 "경량"의 컨테이너는 classpath에 있는 클래스의 조건부 배치를 허용하지만, 배치될 클래스는 명시적, 개별적이어하며, 설정 코드나 일부 XML 설정 파일에 나열되어 있어야 합니다. Web Beans는 XML을 통한 Web Bean 정의 및 설정을 지원하지만 복잡한 설정을 필요로 하지 않는 대부분의 경우, 배치 유형은 전체 Web Beans 설정이 단일 XML 행으로 활성화되게 합니다. 동시에, 코드를 검색하는 개발자는 어떤 배치 시나리오를 Web Bean이 사용할 지를 쉽게 인식할 수 있습니다.
바인딩 어노테이션 및 삽입 지점의 API 유형을 구현하는 모든 Web Beans의 배치 유형을 고려한 후, Web Bean 관리자는 삽입할 하나의 Web Bean을 인식하지 못할 경우 타입 안정적 해상도 알고리즘은 실패하게 됩니다.
UnsatisfiedDependencyException
또는 AmbiguousDependencyException
을 수정하기가 쉽습니다.
UnsatisfiedDependencyException
을 수정하려면, API 유형을 구현하는 Web Bean을 제공하고 삽입 지점의 바인딩 유형을 갖거나 또는 API 유형을 이미 구현하고 있는 Web Bean의 배치 유형을 활성화하고 바인딩 유형을 갖습니다.
AmbiguousDependencyException
을 수정하려면, 두 개의 API 유형 구현 사이에서 구별하기 위해 바인딩 유형을 소개하거나 구현 중 하나의 배치 유형을 변경하여 Web Bean 관리자가 이들 사이에서 선택하기 위해 배치 유형 우선 순위를 사용할 수 있습니다. AmbiguousDependencyException
은 두 개의 Web Beans가 바인딩 유형을 공유하여 동일한 배치 유형을 갖고 있을 때에만 발생할 수 있습니다.
Web Beans에서 의존성 삽입을 사용할 때 유의하셔야 할 사항이 한 가지 더 있습니다.
삽입된 Web Bean 클라이언트는 Web Bean 인스턴스에 직접적인 참조를 유지하지 않습니다.
요청 범위로 바운딩된 Web Bean으로의 직접 참조를 보유하고 있는 애플리케이션 범위에 바운딩된 Web Bean을 가정해 봅시다. 애플리케이션 범위에 바운딩된 Web Bean은 다른 많은 요청 사이에서 공유됩니다. 하지만, 각각의 요청은 요청 범위로 바운딩된 Web Bean의 다른 인스턴스를 확인해야 합니다!
이제 애플리케이션 범위로 바운딩된 Web Bean으로의 직접 참조를 보유하고 있는 세션 범위에 바운딩된 Web Bean을 가정해 봅시다. 때때로 세션 컨텍스트는 메모리를 보다 효과적으로 사용하기 위해 디스크 순서대로 나열됩니다. 하지만, 애플리케이션 범위로 바운딩된 Web Bean 인스턴스는 세션 범위로 바운딩된 Web Bean과 함께 나열되어서는 안됩니다!
따라서, Web Bean은 기본값 범위 @Dependent
를 갖지 않는 한, Web Bean 관리자는 프록시 객체를 통해 삽입된 모든 참조를 Web Bean으로 돌려 놓아야 합니다. 이러한 클라이언트 프록시는 방식 호출을 받는 Web Bean 인스턴스가 현재 컨텍스트와 관련된 인스턴스임을 확인해야 할 책임이 있습니다. 또한 클라이언트 프록시는 Web Beans가 삽입된 다른 Web Beans를 귀납적으로 나열하지 않고 디스크 순서대로 나열한 세션 컨텍스트와 같은 컨텍스트로 바운딩되게 합니다.
Java 언어의 한계로 인해, 일부 Java 유형은 Web Bean 관리자에 의해 프록시될 수 없습니다. 따라서, 삽입 지점 유형이 프록시될 수 없을 경우 Web Bean 관리자는 UnproxyableDependencyException
을 던지게 됩니다.
다음과 같은 Java 유형은 Web Bean 관리자에 의해 프록시될 수 없습니다:
final
이라고 명시되어 있거나 또는 final
방식을 갖는 클래스,
매개 변수 없는 비전용 생성자를 갖지 않는 클래스,
배열 및 기본 유형
UnproxyableDependencyException
을 수정하기 쉽습니다. 간단하게 삽입된 클래스에 매개 변수가 없는 생성자를 추가하고, 인터페이스를 소개하거나, 삽입된 Web Bean의 범위를 @Dependent
로 변경합니다.
애플리케이션은 삽입에 의해 Manager
인터페이스의 인스턴스를 획득할 수 있습니다:
@Current Manager manager;
Manager
객체는 프로그램적으로 Web Bean 인스턴스의 획득을 위한 방식 모음을 제공합니다.
PaymentProcessor p = manager.getInstanceByType(PaymentProcessor.class);
바인딩 어노테이션은 AnnotationLiteral
도우미 클래스를 하부클래스화하여 지정될 수 있으며, 그렇지 않으면 Java에서 어노테이션 유형을 인스턴스화하기 어렵습니다.
PaymentProcessor p = manager.getInstanceByType(PaymentProcessor.class,
new AnnotationLiteral<CreditCard
>(){});
바인딩 유형이 어노테이션 멤버를 갖을 경우, AnnotationLiteral
의 임의의 하부클래스를 사용할 수 없습니다 대신 named 하부 클래스를 생성해야 합니다:
abstract class CreditCardBinding
extends AnnotationLiteral<CreditCard
>
implements CreditCard {}
PaymentProcessor p = manager.getInstanceByType(PaymentProcessor.class,
new CreditCardBinding() {
public void value() { return paymentType; }
} );
Enterprise Web Beans는 EJB 사양에 의해 정의된 모든 수명 주기 콜백을 지원합니다: @PostConstruct
, @PreDestroy
, @PrePassivate
및 @PostActivate
.
심플 Web Beans는 @PostConstruct
및 @PreDestroy
콜백 기능만을 지원합니다.
엔터프라이즈 및 심플 Web Beans는 Java EE 리소스 삽입, EJB 및 JPA 영구적 컨텍스에 대해 @Resource
, @EJB
및 @PersistenceContext
의 사용을 각각 지원합니다. 심플 Web Beans는 @PersistenceContext(type=EXTENDED)
의 사용을 지원하지 않습니다.
@PostConstruct
콜백은 모든 의존성이 삽입된 후에 나타납니다.
특정 종류의 의존성 객체가 있습니다 @Dependent
범위와 함께 Web Beans 객체 또는 이는 실행 가능하게 되기 위해 삽입되는 삽입 지점에 관해 알아야 합니다. 예:
Logger
용 로그 카테고리는 소유하고 있는 객체 클래스에 의존합니다.
헤더 값이나 HTTP 매개 변수 삽입은 삽입 지점에서 어떤 매개 변수 또는 헤더 이름을 지정하였는가에 의존합니다.
EL 표현식 평가 (expression evaluation) 평가의 삽입은 삽입 지점에서 지정된 표현식에 의존합니다.
@Dependent
범위와 함께 Web Bean은 InjectionPoint
인스턴스를 삽입하고 해당 삽입 지점에 관련된 메타데이트를 액세스합니다.
다음 예를 살펴봅시다. 다음과 같은 코드는 프로그램을 리팩토링하기에 취약하고 장황합니다:
Logger log = Logger.getLogger(MyClass.class.getName());
이와 같이 현명한 생산자 방식은 로그 범주를 명시적으로 지정하지 않고 JDK Logger
를 삽입하게 합니다:
class LogFactory {
@Produces Logger createLogger(InjectionPoint injectionPoint) {
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
}
이제 다음을 작성할 수 있습니다:
@Current Logger log;
확신하시지 않습니까? 그러시다면 여기에 두 번째 예제가 있습니다. HTTP 매개 변수를 삽입하려면, 바인딩 유형을 정의해야 합니다:
@BindingType
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface HttpParam {
@NonBinding public String value();
}
다음과 같이 삽입 지점에서 이러한 바인딩 유형을 사용할 수 있습니다:
@HttpParam("username") String username;
@HttpParam("password") String password;
다음의 생산자 방식은 다음과 같이 작업합니다:
class HttpParams
@Produces @HttpParam("")
String getParamValue(ServletRequest request, InjectionPoint ip) {
return request.getParameter(ip.getAnnotation(HttpParam.class).value());
}
}
HttpParam
어노테이션의 value()
멤버는@NonBinding.
을 어노테이션하므로 Web Bean 관리자에 의해 무시됨에 유의하시기 바랍니다.
Web Bean 관리자는 InjectionPoint
인터페이스를 구현하는 내장된 Web Bean을 제공합니다:
public interface InjectionPoint {
public Object getInstance();
public Bean<?> getBean();
public Member getMember():
public <T extends Annotation
> T getAnnotation(Class<T
> annotation);
public Set<T extends Annotation
> getAnnotations();
}
지금까지 범위 유형 어노테이션의 여러 가지 예를 살펴보았습니다. Web Bean의 범위는 Web Bean 인스턴스의 수명주기를 결정합니다. 또한 범위는 어떤 클라이언트가 어떤 Web Bean 인스턴스를 참조하게 할 지를 결정합니다. Web Beans 사양에 따라 범위는 다음을 결정합니다:
범위와 함께 Web Bean의 새로운 인스턴스가 생성될 시기
범위와 함께 Web Bean의 기존 인스턴스가 제거될 시기
삽입된 어떤 참조가 범위와 함께 Web Bean 인스턴스를 참조하는 지
예를 들어, Web Bean 세션 범위가 있을 경우, CurrentUser
, 동일한 HttpSession
컨텍스트에서 호출되는 모든 Web Beans는 동일한 CurrentUser
인스턴스를 확인하게 됩니다. 이러한 인스턴스는 세션에서 CurrentUser
가 처음으로 필요할 때 자동으로 생성되고 세션이 끝나면 자동으로 삭제됩니다.
Web Beans는 extensible context model을 특징으로 합니다. 새로운 범위 유형 어노테이션을 생성하여 새로운 범위를 정의할 수 있습니다:
@Retention(RUNTIME)
@Target({TYPE, METHOD})
@ScopeType
public @interface ClusterScoped {}
물론 이는 이러한 작업 중 쉬운 부분입니다. 이러한 범위 유형을 유용하게 하려면, 범위를 구현하는 Context
객체를 정의해야 합니다! Context
구현은 아주 기술적인 작업으로, 프레임워크 개발 만을 목적으로 합니다.
Web Bean 범위를 지정하기 위해 Web Bean 구현 클래스에 범위 유형 어노테이션을 적용할 수 있습니다:
@ClusterScoped
public class SecondLevelCache { ... }
주로, Web Beans의 내장된 범위 중 하나를 사용하게 됩니다.
Web Beans는 네 가지 내장된 범위를 정의합니다:
@RequestScoped
@SessionScoped
@ApplicationScoped
@ConversationScoped
Web Beans를 사용하는 웹 애플리케이션의 경우:
servlet 요청은 활성 요청, 세션 및 애플리케이션 범위에 액세스합니다
JSF 요청은 활성 컨버세이션 범위에 액세스합니다.
요청 및 애플리케이션 범위도 활성화되어 있습니다:
EJB 원격 방식의 호출시
EJB 시간 초과시
메세지 구동 빈에 메세지 전달시
웹 서비스 호출시
애플리케이션이 활성 컨텍스트가 없는 범위와 함께 Web Bean을 호출하고자할 경우, 런타임시 ContextNotActiveException
은 Web Bean 관리자에 의해 넘기게 됩니다.
네 개의 내장된 범위 중 세 개는 모든 Java EE 개발자에게 익숙하므로, 여기서 다루지 않겠습니다. 하지만 이 중 하나의 범위 새로운 것입니다.
Web Beans 컨버세이션 범위는 시스템 사용자와 관련된 상태를 보유하고 있는 전통 세션 범위와 유사하며, 서버에 여러 가지 요청을 보냅니다. 하지만, 세션 범위와 다르게 컨버세이션 범위는 다음과 같은 사항을 갖습니다:
애플리케이션에 의해 명시적으로 경계를 정합니다
JSF 애플리케이션에 있는 특정 웹 브라우저 탭과 관련한 상태를 유지합니다.
컨버세이션은 사용자 관점에서의 작업 단위, 작업 내용을 나타냅니다. 컨버세이션 컨텍스트는 현재 사용자가 작업하고 있는 것과 관련된 상태를 유지합니다. 사용자가 동시에 여러가지 작업을 실행하고 있을 경우, 여러 개의 컨버세이션이 있게 됩니다.
컨버세이션 컨텍스트는 JSF 요청 시 활성화되어 있습니다. 하지만 대부분의 컨버세이션은 요청 마지막에 삭제됩니다. 컨버세이션이 여러 가지 요청을 통해 상태를 유지해야 할 경우, 장기 실행 컨버세이션으로 요청되어야 합니다.
Web Beans는 JSF 애플리케이션에 있는 컨버세이션 수명 주기를 제어하기 위한 내장된 Web Bean을 제공합니다. 이러한 Web Bean은 삽입에 의해 획득될 수 있습니다:
@Current Conversation conversation;
장기 실행 컨버세이션으로의 최근 요청과 관련된 컨버세이션을 활성화하려면, 애플리케이션 코드에서 begin()
방식을 호출합니다. 현재 요청의 마지막에 삭제를 위해 장기 실행 컨버세이션 컨텍스트를 스케줄하려면 end()
를 호출합니다.
다음의 예에서, 컨버세이션 범위 Web Bean은 관련 된 컨버세이션을 제어합니다:
@ConversationScoped @Stateful
public class OrderBuilder {
private Order order;
private @Current Conversation conversation;
private @PersistenceContext(type=EXTENDED) EntityManager em;
@Produces public Order getOrder() {
return order;
}
public Order createOrder() {
order = new Order();
conversation.begin();
return order;
}
public void addLineItem(Product product, int quantity) {
order.add( new LineItem(product, quantity) );
}
public void saveOrder(Order order) {
em.persist(order);
conversation.end();
}
@Remove
public void destroy() {}
}
Web Bean은 Conversation
API를 사용하여 수명 주기를 제어할 수 있습니다. 하지만 일부 다른 Web Beans는 다른 객체에 완전히 의존하는 수명 주기를 갖습니다.
컨버세이션 컨텍스트는 JSF faces 요청 (JSF 양식 제출)과 함께 자동으로 보급됩니다. 예를 들어, 링크를 통한 네비게이션과 같이 이는 non-faces 요청과 함께 자동으로 보급되지 않습니다.
요청 매개 변수로서 컨버세이션의 고유 식별자를 포함하여 컨버세이션이 non-faces 요청과 함께 보급되도록 강제할 수 있습니다. Web Beans 사양은 이를 사용하기 위해 cid
라는 요청 매개 변수를 가집니다. 컨버세이션의 고유 식별자는 Conversation
객체에서 획득할 수 있으며, conversation
이라는 Web Beans 이름을 갖습니다.
따라서, 다음과 같은 링크가 컨버세이션을 보급합니다:
<a href="/addProduct.jsp?cid=#{conversation.id}" >Add Product</a >
Web Bean 관리자는 컨버세이션이 장기 실행으로 표시되어 있지 않아도, 리다이렉트를 통해 컨버세이션을 보급해야 합니다. 이는 "플래시" 객체와 같은 깨지기 쉬운 구조에 의지하지 않고 일반적인 POST-then-redirect 패턴 쉽게 구현하게 합니다. 이러한 경우 Web Bean 관리자는 리다이렉트 URL에 요청 매개 변수를 자동으로 추가합니다.
Web Bean 관리자에게는 리소스를 보관하기 위해 컨텍스트에 있는 모든 상태 및 컨버세이션을 삭제할 수 있는 권한이 있습니다. Web Bean 관리자 구현은 주로 시간 초과에 기반하여 이를 실행합니다 이는 Web Beans 사양에 의해 요청되지 않습니다. 시간 초과는 컨버세이션이 삭제된 후 비활성화 기간을 말합니다.
Conversation
객체는 시간 초과를 설정하기 위한 방식을 제공합니다. 이는 Web Bean 관리자에게 도움이 되며, 설정 사항을 무시하셔도 상관 없습니다.
conversation.setTimeout(timeoutInMillis);
네 가지 내장된 범위에 더하여, Web Beans는 dependent pseudo-scope라는 기능을 특징으로 합니다. 이는 범위 유형을 명시하지 않는 Web Bean에 대한 기본값 범위입니다.
예를 들어, Web Bean에는 @Dependent
범위 유형이 있습니다:
public class Calculator { ... }
Web Bean의 삽입 지점이 의존적 Web Bean을 해결할 때, 의존적 Web Bean의 새로운 인스턴스는 처음으로 Web Bean이 초기화될 때 마다 생성됩니다. 의존적 Web Beans의 인스턴스는 다른 Web Bean 사이에서나 또는 다른 삽입 지점 간에 공유되지 않습니다. 이는 일부 다른 Web Bean 인스턴스에 대해 의존적 객체입니다.
의존하는 인스턴스가 삭제되면 의존적 Web Bean 인스턴스가 삭제됩니다.
클래스 또는 EJB bean이 일부 다른 범위 유형과 함께 Web Bean으로 명시되어 있어도, Web Beans는 Java 클래스 또는 EJB bean의 의존적 인스턴스를 쉽게 획득할 수 있게 합니다.
내장된 @New
바인딩 어노테이션은 삽입 지점에서 의존적 Web Bean의 암시적 정의를 허용합니다. 다음과 같은 삽입 영역을 명시한다고 가정합시다:
@New Calculator calculator;
@Dependent
범위, @New
바인딩 유형, Calculator
API 유형, Calculator
구현 클래스, @Standard
배치 유형과 함께 Web Bean은 암시적으로 정의됩니다.
Calculator
가 다른 범위 유형과 함께 이미 명시되어 있어도 이는 사실입니다, 예:
@ConversationScoped
public class Calculator { ... }
다음의 삽입 속성은 다른 Calculator
인스턴스를 갖습니다:
public class PaymentCalc {
@Current Calculator calculator;
@New Calculator newCalculator;
}
calculator
영역에는 Calculator
의 컨버세이션 범위 인스턴스가 삽입되어 있습니다. newCalculator
영역에는 PaymentCalc
소유로 바운딩된 수명 주기와 함께 Calculator
의 새로운 인스턴스가 삽입되어 있습니다.
특히 이러한 기능은 다음 장에서 다루게 될 생산자 방식에서 유용합니다.
생산자 방식은 Web Bean 관리자가 애플리케이션 대신 인스턴스 객체에 응답할 때 발생할 수 있는 특정한 한계를 극복할 수 있게 합니다. Web Beans이 아닌 객체를 Web Beans 환경으로 통합하기 위한 가장 쉬운 방법이 있습니다. (12장. XML을 사용하여 Web Beans 정의 에서 두번째 방법에 대해 살펴보겠습니다.)
spec에 의하면:
A Web Beans producer method acts as a source of objects to be injected, where:
the objects to be injected are not required to be instances of Web Beans,
the concrete type of the objects to be injected may vary at runtime or
the objects require some custom initialization that is not performed by the Web Bean constructor
For example, producer methods let us:
expose a JPA entity as a Web Bean,
expose any JDK class as a Web Bean,
define multiple Web Beans, with different scopes or initialization, for the same implementation class, or
vary the implementation of an API type at runtime.
In particular, producer methods let us use runtime polymorphism with Web Beans. As we've seen, deployment types are a powerful solution to the problem of deployment-time polymorphism. But once the system is deployed, the Web Bean implementation is fixed. A producer method has no such limitation:
@SessionScoped
public class Preferences {
private PaymentStrategyType paymentStrategy;
...
@Produces @Preferred
public PaymentStrategy getPaymentStrategy() {
switch (paymentStrategy) {
case CREDIT_CARD: return new CreditCardPaymentStrategy();
case CHEQUE: return new ChequePaymentStrategy();
case PAYPAL: return new PayPalPaymentStrategy();
default: return null;
}
}
}
Consider an injection point:
@Preferred PaymentStrategy paymentStrat;
This injection point has the same type and binding annotations as the producer method, so it resolves to the producer method using the usual Web Beans injection rules. The producer method will be called by the Web Bean manager to obtain an instance to service this injection point.
.생산자 방식의 기본값 범위는 @Dependent
로 되어 있으므로, 매 번 Web Bean 관리자가 이러한 영역 또는 동일한 생산자 방식으로 해결되는 다른 영역을 삽입할 때 마다 호출됩니다. 따라서, 각각의 사용자 세션에 대해 PaymentStrategy
객체의 인스턴스가 여러개 있을 수 있습니다.
이러한 기능을 변경하려면, @SessionScoped
어노테이션 방식을 추가할 수 있습니다.
@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy() {
...
}
이제 생산자 방식이 호출되면, 반환된 PaymentStrategy
는 세션 컨텍스트로 바운드됩니다. 동일한 세션에서 생산자 방식은 다시 호출되지 않습니다.
위의 코드에 한 가지 문제가 있을 수 있습니다. CreditCardPaymentStrategy
구현은 Java new
연산자를 사용하여 인스턴스화됩니다. 애플리케이션에 의해 직접 인스턴스화된 객체는 의존성 삽입의 장점을 취할 수 없으며 인터셉터를 갖지 못합니다.
이러한 방식을 원하지 않을 경우, 의존성 삽입을 생산자 방식으로 사용하여 Web Bean 인스턴스를 획득할 수 있습니다:
@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,
ChequePaymentStrategy cps,
PayPalPaymentStrategy ppps) {
switch (paymentStrategy) {
case CREDIT_CARD: return ccps;
case CHEQUE: return cps;
case PAYPAL: return ppps;
default: return null;
}
}
CreditCardPaymentStrategy
가 요청 범위 Web Bean이면 어떻게 합니까? 이럴 경우 생산자 방식은 현재 요청 범위 임스턴스를 세선 범위로 "활성화되게" 됩니다. 이는 버그입니다! 요청 범위 객체는 세션이 종료되기 전 Web Bean 관리자에 의해 삭제되지만, 객체에 대한 참조는 세션 범위에 "남아 있게" 됩니다. 이러한 오류는 Web Bean 관리자에 의해 검출되지 않으므로 생산자 방식에 Web Bean 인스턴스를 반환할 경우 각별히 주의하시기 바랍니다!
이러한 버그를 해결할 수 있는 세 가지 방법이 있습니다. CreditCardPaymentStrategy
구현 범위를 변경할 수 있지만, Web Bean의 클라이언트에 영향을 미칠 수 있습니다. 보다 나은 방법으로 생산자 방식의 범위를 @Dependent
또는 @RequestScoped
로 변경하는 것입니다.
하지만 보다 일반적인 방법은 특별한 @New
바인딩 어노테이션을 사용하는 것입니다.
다음과 같은 생산자 방식을 고려합니다:
@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps,
@New ChequePaymentStrategy cps,
@New PayPalPaymentStrategy ppps) {
switch (paymentStrategy) {
case CREDIT_CARD: return ccps;
case CHEQUE: return cps;
case PAYPAL: return ppps;
default: return null;
}
}
CreditCardPaymentStrategy
의 새로운 의존성 인스턴스가 생성되면, 생산자 방식으로 전달하고, 생산자 방식에 의해 반환된 후, 마지막으로 세션 컨텍스트로 바운딩됩니다. 의존성 객체는 세션 마지막에 Preferences
객체가 삭제될 때 까지 삭제되지 않습니다.
Web Beans의 첫번째 주요 기능은 느슨한 연결 (loose coupling)입니다. 이러한 느슨한 연결 기능을 실행하기 위한 세가지 방식은 이미 알려져 있습니다:
배치 유형은 배치 시간 다형성을 활성화합니다
생산자 방식은 런타임 다형성을 활성화합니다
컨텍스트 수명주기 관리는 Web Bean 수명 주기를 연결 해제합니다.
이러한 기술로 클라이언트 및 서버의 느슨한 연결을 활성화할 수 있습니다. 클라이언트는 더이상 API 구현으로 바운딩할 수 없으며, 서버 객체의 수명주기를 관리할 수 없습니다. 이러한 접근으로 상태 유지 객체가 서비스하는 것 처럼 상호 작용하게 합니다.
느슨한 연결로 시스템이 보다 동적으로 되게 할 수 있습니다. 시스템은 잘 정의된 방식에서의 변경 사항에 대응할 수 있습니다. 위에 나열된 기능을 변함없이 제공하기 위한 이전의 프레임워크는 타입 안정성을 희생하여 이를 실행하였습니다. Web Beans는 타입 안정적 방식에서의 느슨한 연결을 실행하기 위한 첫번째 기술입니다.
Web Beans는 느슨한 연결 기능을 촉진하기 위해 세 가지 중요한 기능을 추가로 제공합니다:
인터셉터는 비지니스 로직으로 부터의 기술적 문제를 연결 해제합니다
데코레이터는 일부 비지니스 문제를 연결 해제하기 위해 사용될 수 있습니다.
이벤트 통지는 이벤트 소비자로 부터 이벤트 생산자를 연결 해제합니다.
먼저 인터셉터에 대해 살펴봅시다.
Web Beans는 EJB 3.0의 기본 인터셉터 구조를 재사용하여, 두 가지 방향으로 기능을 확장합니다:
Web Bean에는 세션 beans 만이 아니라 인터셉터도 있을 수 있습니다.
Web Beans는 Web Beans에 인터셉터를 바인딩하기 위해 보다 복잡한 어노테이션 기반 방식을 특징으로 합니다.
EJB 사양은 두 종류의 인터셉션 지점을 정의합니다:
비지니스 방식 인터셉터
수명주기 콜백 인터셉터
비지니스 방식 인터셉터는 Web Bean 클라이언트에 의해 Web Bean 방식 호출에 적용됩니다:
public class TransactionInterceptor {
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
수명 주기 콜백 인터셉터는 컨테이너에 의해 수명 주기 콜백 호출에 적용됩니다:
public class DependencyInjectionInterceptor {
@PostConstruct public void injectDependencies(InvocationContext ctx) { ... }
}
인터셉터 클래스는 수명 주기 콜백 및 비지니스 방식 모두를 차단할 수 있습니다.
Web Beans의 일부는 트랜젝션할 수 있음을 명시하고자 한다고 가정합니다. 처음으로 해야할 것은 어떤 Web Beans에 관심이 있는 지를 지정하기 위해 인터셉터 바인딩 어노테이션을 합니다:
@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {}
ShoppingCart
가 트랜젝션 객체임을 쉽게 지정할 수 있습니다:
@Transactional
public class ShoppingCart { ... }
원하실 경우, 하나의 방식 만이 트랙젝션 가능하도록 지정할 수 있습니다:
public class ShoppingCart {
@Transactional public void checkout() { ... }
}
행을 따라 어딘가에 이러한 트랜젝션 관리 측면을 제공하기 위해 실제적으로 인터셉터를 구현해야 합니다. 해야 할 작업은 표준 EJB 인터셉터를 생성하고 이를 @Interceptor
및 @Transactional
로 어노테이션하는 것입니다.
@Transactional @Interceptor
public class TransactionInterceptor {
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
모든 Web Beans 인터셉터는 심플 Web Beans으로, 의존성 삽입및 컨텍스트 수명 주기 관리의 장점을 취할 수 있습니다.
@ApplicationScoped @Transactional @Interceptor
public class TransactionInterceptor {
@Resource Transaction transaction;
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
여러 인터셉터는 동일한 인터셉터 바인딩 유형을 사용할 수 있습니다.
마지막으로 web-beans.xml
에서 인터셉터를 활성화해야 합니다.
<Interceptors>
<tx:TransactionInterceptor/>
</Interceptors
>
왜 각진 괄호를 써야 합니까?
XML 선언으로 두 가지 문제를 해결합니다:
이는 시스템에서 모든 인터셉터에 대한 전체적인 순서를 지정할 수 있도록 활성화하며, 결정적인 작업를 확인합니다
배치시 인터셉터 클래스를 활성화 또는 비활성화하게 합니다.
예를 들어, TransactionInterceptor
이전에 보안 인터셉터를 실행하도록 지정할 수 있습니다.
<Interceptors>
<sx:SecurityInterceptor/>
<tx:TransactionInterceptor/>
</Interceptors
>
또는 테스트 환경에서 두 가지 모두를 비활성화시킬 수 있습니다!
@Transactional
어노테이션에 정보를 추가하고자 한다고 가정합시다:
@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {
boolean requiresNew() default false;
}
Web Beans는 requiresNew
값을 사용하여 두 개의 다른 인터셉터 TransactionInterceptor
와 RequiresNewTransactionInterceptor
중에서 선택하게 됩니다.
@Transactional(requiresNew=true) @Interceptor
public class RequiresNewTransactionInterceptor {
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
다음과 같이 RequiresNewTransactionInterceptor
를 사용할 수 있습니다:
@Transactional(requiresNew=true)
public class ShoppingCart { ... }
한 개의 인터샙터만이 있고 인터셉터를 바인딩할 때 requiresNew
값을 무시하기 위한 관리자를 원할 경우에는 @NonBinding
어노테이션을 사용할 수 있습니다:
@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Secure {
@NonBinding String[] rolesAllowed() default {};
}
일반적으로 여러개의 인터셉터를 Web Bean에 바인딩하기 위해 인터셉터 바인딩 유형의 조합을 사용합니다. 예를 들어, 다음과 같은 명시를 사용하여 동일한 Web Bean에 TransactionInterceptor
및 SecurityInterceptor
를 바인딩할 수 있습니다:
@Secure(rolesAllowed="admin") @Transactional
public class ShoppingCart { ... }
하지만 매우 복잡한 경우 인터셉터 자체가 인터셉터 바인딩 유형의 조합을 일부 지정할 수 있습니다:
@Transactional @Secure @Interceptor
public class TransactionalSecureInterceptor { ... }
그 후 이러한 인터셉터는 다음과 같은 조합 중 하나를 사용하여 checkout()
방식에 바운딩될 수 있습니다:
public class ShoppingCart {
@Transactional @Secure public void checkout() { ... }
}
@Secure
public class ShoppingCart {
@Transactional public void checkout() { ... }
}
@Transactionl
public class ShoppingCart {
@Secure public void checkout() { ... }
}
@Transactional @Secure
public class ShoppingCart {
public void checkout() { ... }
}
어노테이션에 대한 Java 언어 지원 한계는 어노테이션 상속의 결여입니다. 실제로 어노테이션은 재사용 기능이 내장되어 있어 이러한 기능이 작동하게 해야 합니다:
public @interface Action extends Transactional, Secure { ... }
다행히도 Web Beans는 이러한 생략된 Java의 기능을 해결하여 하나의 인터셉터 바인딩 유형을 다른 인터셉터 바인딩 유형과 어노테이션할 수 있습니다. 인터셉터 바인딩은 트렌젝션 가능하여 첫번째 인터셉터 바인딩이 있는 Web Bean은 메타 어노테이션으로 명시된 인터셉터 바인딩을 상속할 수 있습니다.
@Transactional @Secure
@InterceptorBindingType
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action { ... }
@Action
으로 어노테이션된 Web Bean은 TransactionInterceptor
및 SecurityInterceptor
로 바운딩됩니다. (TransactionalSecureInterceptor
이 있을 경우 이것으로 바운딩됩니다.)
EJB 사양에 의해 정의된 @Interceptors
어노테이션은 엔터프라이즈 및 심플 Web Beans 모두를 지원합니다. 예:
@Interceptors({TransactionInterceptor.class, SecurityInterceptor.class})
public class ShoppingCart {
public void checkout() { ... }
}
하지만, 이러한 방식은 다음과 같은 결점을 갖습니다:
인터셉터 구현은 비지니스 코드에서 하드코어되어 있습니다
인터셉터는 배치시 쉽게 비활성화할 수 없습니다,
인터셉터 순서는 비전역적입니다 이는 클래스 레벨로 열거된 인터셉터 순서에 의해 결정됩니다.
따라서 Web Beans 형식 인터셉터 바인딩을 사용할 것을 권장합니다.
인터셉터는 유형 시스템에 직교 되어 있는 문제를 분리하고 캡쳐하는 강력한 방법입니다. 인터셉터는 모든 Java 유형 호출을 차단할 수 있습니다. 이는 트랜젝션 관리 및 보안과 같은 기술적 문제를 해결하는데 유용합니다. 하지만, 본래 인터셉터는 차단한 이벤트의 실제적 시멘틱을 인식하지 않습니다. 따라서, 인터셉터는 비지니스 관련 문제를 분리하기 위한 도구로는 적합하지 않습니다.
역으로 기능하는 것이 데코레이터입니다. 데코레이터는 특정 Java 인터페이스에 대해서만 호출을 차단하며, 인터페이스에 부착된 모든 시멘틱을 인식합니다. 이는 일부 비지니스 문제를 모델화하기 위해 데코레이터를 완벽한 도구로 만듭니다. 또한 데코레이터는 인터셉터의 일반적 기능을 갖지 않습니다. 데코레이터는 여러 이질적 유형을 초월하는 기술적 문제를 해결할 수 없습니다.
어카운트를 나타내는 인터페이스가 있다고 가정합니다:
public interface Account {
public BigDecimal getBalance();
public User getOwner();
public void withdraw(BigDecimal amount);
public void deposit(BigDecimal amount);
}
시스템에서 여러 다른 Web Beans는 Account
인터페이스를 구현합니다. 하지만, 일반적인 법적 요구조건이 있으며, 모든 종류의 어카운트의 경우, 대용량 트랜젝션은 특정 로그로 시스템에 의해 기록되어야 합니다. 이는 데코레이터의 뛰어난 작업 기능입니다.
데코레이터는 심플 Web Bean으로 유형을 구현하고 @Decorator
를 어노테이션합니다.
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
@Decorates Account account;
@PersistenceContext EntityManager em;
public void withdraw(BigDecimal amount) {
account.withdraw(amount);
if ( amount.compareTo(LARGE_AMOUNT)
>0 ) {
em.persist( new LoggedWithdrawl(amount) );
}
}
public void deposit(BigDecimal amount);
account.deposit(amount);
if ( amount.compareTo(LARGE_AMOUNT)
>0 ) {
em.persist( new LoggedDeposit(amount) );
}
}
}
기타 다른 심플 Web Beans와 다르게, 데코레이터는 추상클래스일 수 도 있습니다. 데코레이터된 인터페이스의 특정 방식에 대해 데코레이터가 특별히 해야할 것이 없을 경우, 이 방식을 구현하실 필요가 없습니다.
모든 데코레이터는 위임 속성 기능을 갖습니다. 위임 속성의 유형 및 바인딩 유형은 어떤 Web Beans에 데코레이터를 바운딩할 지를 결정합니다. 위임 속성 유형은 데코레이터에 의해 구현된 모든 인터페이스를 구현 또는 확장해야 합니다.
이러한 위임 속성은 Account
를 구현하는 모든 Web Beans로 바인딩하는 데코레이터를 지정합니다.
@Decorates Account account;
위임 속성은 바인딩 어노테이션을 지정할 수 도 있습니다. 그 후 데코레이터는 동일한 바인딩을 사용하여 Web Beans로 바운딩되게 됩니다.
@Decorates @Foreign Account account;
데코레이터는 다음과 같은 사항이 있는 Web Bean으로 바인딩됩니다:
API 유형과 같은 위임 속성 유형
위임 속성에 의해 명시된 모든 바인딩 유형
데코레이터는 위임 속성을 호출할 수 있으며, 인터셉터에서 InvocationContext.proceed()
를 호출하는 것과 동일한 영향을 미칩니다.
web-beans.xml
에서 데코레이터를 활성화해야 합니다.
<Decorators>
<myapp:LargeTransactionDecorator/>
</Decorators
>
이러한 명시 사항은 데코레이터에 대해 <Interceptors>
명시가 인터셉터에 대해 실행하는 것과 동일한 목적을 실행합니다:
이는 시스템에서 모든 데코레이터에 대한 전체적인 순서를 지정할 수 있도록 활성화하며, 결정적인 작업를 확인합니다
배치시 데코레이터 클래스를 활성화 또는 비활성화하게 합니다.
데코레이터를 적용하기 전 해당 방식의 인터셉터를 호출합니다.
Web Beans 이벤트 통지 기능은 Web Beans가 완전 연결 해제 방식으로 상호 작용하게 합니다. 이벤트 생산자는 이벤트를 제기한 후 Web Bean 관리자에 의해 이벤트 옵저버로 전달합니다. 이러한 기본적인 스키마는 옵저버/옵저버 패턴과 유사하게 들이지만, 몇 가지 다른 부분이 있습니다:
이벤트 생산자만 옵저버에서 연결 해제되는 것이 아니라; 옵저버도 생산자에서 완전하게 연결 해제됩니다.
옵저버는 "선택자" 조합을 지정하여 이벤트 통지 모음의 범위를 좁힙니다.
옵저버는 바로 통지하거나 또는 현재 트랜젝션이 끝날때 까지 이벤트 전송이 지연되도록 지정할 수 있습니다.
옵저버 방식은 매개변수 어노테이션 @Observes
를 사용하는 Web Bean 방식입니다.
public void onAnyDocumentEvent(@Observes Document document) { ... }
어노테이션된 매개 변수는 이벤트 매개 변수라고 부릅니다. 이벤트 매개 변수의 유형은 옵저버된 이벤트 유형입니다. 옵저버 방식은 Web Beans 바인딩 유형의 인스터스인 "선택자"를 지정할 수 있습니다. 바인딩 유형이 이벤트 선택자로 사용될 경우, 이를 이벤트 바인딩 유형이라고 부릅니다.
@BindingType
@Target({PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface Updated { ... }
이벤트 매개 변수를 어노테이션하여 옵저버 방식의 이벤트 바인딩을 지정합니다:
public void afterDocumentUpdate(@Observes @Updated Document document) { ... }
옵저버 방식은 어떤 이벤트 바인딩도 지정할 필요가 없습니다 이러한 경우 특정 유형의 모든 이벤트에 관심을 갖게 됩니다. 이벤트 바인딩을 지정하지 않을 경우, 이러한 이벤트 바인딩이 있는 이벤트에만 관심을 갖게 됩니다.
옵저버 방식은 추가 매개 변수를 갖을 수 있으며, 이는 일반적인 Web Beans 방식 매개 변수 삽입 시멘틱에 따라 삽입됩니다:
public void afterDocumentUpdate(@Observes @Updated Document document, User user) { ... }
이벤트 생산자는 삽입을 통해 이벤트 통지 객체를 갖을 수 있습니다:
@Observable Event<Document
> documentEvent
@Observable
어노테이션은 @Dependent
범위 및 @Standard
배치 유형, Web Bean 관리자에 의해 제공되는 구현으로 Web Bean을 정의합니다.
생산자는 Event
인터페이스의 fire()
방식을 호출하여 이벤트를 제기하고, 이벤트 객체를 전달합니다:
documentEvent.fire(document);
이벤트 객체는 와일드카드 유형 매개변수나 또는 유형 변수가 없는 Java 클래스의 인스턴스가 될 수 도 있습니다. 이벤트는 다음과 같은 사항을 갖는 모든 옵저버 방식에 전달됩니다:
이벤트 객체를 할당할 수 있는 이벤트 매개 변수를 갖습니다,
이벤트 바인딩 없음을 지정합니다.
Web Bean 관리자는 모든 옵저버 방식을 호출하여, 이벤트 매개 변수 값으로 이벤트 객체를 전달합니다. 옵저버 방식이 예외 처리를 넘기게 될 경우, Web Bean 관리자는 옵저버 방식 호출을 중단하고 예외 처리는 fire()
방식에 의해 다시 넘기게 됩니다.
"선택자"를 지정하려면, 이벤트 생산자가 이벤트 바인딩 유형을 fire()
방식에 전달해야 합니다:
documentEvent.fire( document, new AnnotationLiteral<Updated
>(){} );
Java에서 실행하기 어려웠던 도우미 클래스 AnnotationLiteral
은 바인딩 유형 인라인을 인스턴스화할 수 있게 합니다.
이벤트는 모든 옵저버 방식으로 전달됩니다:
이벤트 객체를 할당할 수 있는 이벤트 매개 변수를 갖습니다,
이는 fire()
에 전달된 이벤트 바인딩에 대한 모든 이벤트 바인딩 예외 사항을 지정하지 않습니다.
다른 방법으로 이벤트 바인딩은 이벤트 통지 삽입 지점을 어노테이션하여 지정될 수 도 있습니다:
@Observable @Updated Event<Document
> documentUpdatedEvent
이러한 Event
인스턴스를 통해 해제된 모든 이벤트는 어노테이션된 이벤트 바인딩을 갖습니다. 이벤트는 모든 옵저버 방식에 전달됩니다:
이벤트 객체를 할당할 수 있는 이벤트 매개 변수를 갖습니다,
이는 이벤트 통지 삽입 지점의 어노트에션된 이벤트 바인딩이나 또는 fire()
에 전달된 이벤트 바인딩에 대한 모든 이벤트 바인딩 예외 사항을 지정하지 않습니다.
종종 이벤트 옵저버를 동적으로 등록하는 것이 유용합니다. 애플리케이션은 Observer
인터페이스를 구현하고 observe()
방식을 호출하여 이벤트 통지와 함께 인스턴스를 등록할 수 있습니다.
documentEvent.observe( new Observer<Document
>() { public void notify(Document doc) { ... } } );
이벤트 바인딩 유형은 인벤트 통지 삽입 지점에 의해 지정되거나 observe()
방식에 이벤트 바인딩 유형 인스턴스를 전달하여 지정할 수 있습니다:
documentEvent.observe( new Observer<Document
>() { public void notify(Document doc) { ... } },
new AnnotationLiteral<Updated
>(){} );
이벤트 바인딩 유형은 어노테이션 멤버를 갖을 수 있습니다:
@BindingType
@Target({PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface Role {
RoleType value();
}
멤버 값은 옵저버에게 전달되는 메세지의 범위를 좁히는데 사용됩니다:
public void adminLoggedIn(@Observes @Role(ADMIN) LoggedIn event) { ... }
이벤트 바인딩 유형 멤버는 이벤트 통지 삽입 지점에 있는 어노테이션을 통해 이벤트 생산자에의해 정적으로 지정될 수 있습니다:
@Observable @Role(ADMIN) Event<LoggedIn
> LoggedInEvent;}}
다른 방법으로, 이벤트 바인딩 유형 멤버 값은 이벤트 생산자에 의해 동적으로 지정될 수 있습니다. AnnotationLiteral
의 추상화 하부클래스를 작성하여 시작합니다:
abstract class RoleBinding
extends AnnotationLiteral<Role
>
implements Role {}
이벤트 생산자는 이러한 클래스의 인스턴스를 fire()
로 전달합니다:
documentEvent.fire( document, new RoleBinding() { public void value() { return user.getRole(); } } );
이벤트 바인딩 유형은 통합할 수 있습니다, 예:
@Observable @Blog Event<Document
> blogEvent;
...
if (document.isBlog()) blogEvent.fire(document, new AnnotationLiteral<Updated
>(){});
이러한 이벤트가 발생하면, 다음과 같은 옵저버 방식 모두가 통지되게 됩니다:
public void afterBlogUpdate(@Observes @Updated @Blog Document document) { ... }
public void afterDocumentUpdate(@Observes @Updated Document document) { ... }
public void onAnyBlogEvent(@Observes @Blog Document document) { ... }
public void onAnyDocumentEvent(@Observes Document document) { ... }}}
트랜잭션 옵저버는 이벤크가 제기된 트랜잭션의 완료 단계 이전 또는 이후 동안 이벤트 통지를 받습니다. 예를 들어, 다음과 같은 옵저버 방식은 트랜잭션이 Category
크리를 성공적으로 업데이트했을 경우에만 애플리케이션 컨텍스트에서 캐시된 쿼리 결과 모음을 새로고침해야 합니다:
public void refreshCategoryTree(@AfterTransactionSuccess @Observes CategoryUpdateEvent event) { ... }
세 가지 종류의 트랜잭션 옵저버가 있습니다:
트랜잭션의 완료 단계 이후 동안 트랜잭션이 성공적으로 완료했을 경우에만, @AfterTransactionSuccess
옵저버를 호출합니다.
트랜잭션의 완료 단계 이후 동안 트랜잭션이 성공적으로 완료하지 않을 경우에만, @AfterTransactionFailure
옵저버를 호출합니다.
트랜잭션의 완료 단계 이후 동안 @AfterTransactionCompletion
옵저버를 호출합니다
트랜잭션의 완료 단계 이전 동안 @BeforeTransactionCompletion
옵저버를 호출합니다
트랜잭션 옵저버는 Web Beans와 같은 상태 유지 객체 모델에서 아주 중요합니다. 이는 단일 원자성 트랜잭션보다 오래 지속되기 때문입니다.
애플리케이션 범위에 있는 JPA 쿼리 결과 모음을 캐시했다고 가정합니다:
@ApplicationScoped @Singleton
public class Catalog {
@PersistenceContext EntityManager em;
List<Product
> products;
@Produces @Catalog
List<Product
> getCatalog() {
if (products==null) {
products = em.createQuery("select p from Product p where p.deleted = false")
.getResultList();
}
return products;
}
}
때때로 Product
는 생성 또는 삭제됩니다. 이러한 상황이 발생하면, Product
카탈로그를 새로고침해야 합니다. 하지만, 이러한 새로 고침을 실행하기 전 트랜젝션이 성공적으로 완료할 때 까지 기다리셔야 합니다!
Product
를 생성 및 삭제하는 Web Bean은 이벤트를 제기할 수 있습니다, 예:
@Stateless
public class ProductManager {
@PersistenceContext EntityManager em;
@Observable Event<Product
> productEvent;
public void delete(Product product) {
em.delete(product);
productEvent.fire(product, new AnnotationLiteral<Deleted
>(){});
}
public void persist(Product product) {
em.persist(product);
productEvent.fire(product, new AnnotationLiteral<Created
>(){});
}
...
}
Catalog
는 트랜잭션을 성공적으로 완료한 후에 이벤트를 옵저버할 수 있습니다:
@ApplicationScoped @Singleton
public class Catalog {
...
void addProduct(@AfterTransactionSuccess @Observes @Created Product product) {
products.add(product);
}
void addProduct(@AfterTransactionSuccess @Observes @Deleted Product product) {
products.remove(product);
}
}
Web Beans의 두번째 주요 기능은 강한 타이핑 (strong typing)입니다. Web Bean의 의존성, 인터셉터, 데코레이터에 관한 정보 및 이벤트 생산자에 대한 이벤트 소비자에 관한 정보는 컴파일러에 의해 사용할 수 있는 타입 안정적 Java 구성 요소에 들어 있습니다.
Web Beans 코드에서 문자열 기반 식별자를 보실 수 없습니다. 그 이유는 프레임워크가 "관례에 의한 설정"이라고 부르는 기본값 규칙을 사용하여 이를 숨기려하기 때문이 아니라 시작할 수 있는 문자열이 없기 때문입니다!
이러한 접근 방식의 장점은 어떤 IDE도 특정 도구 없이 자동 완성, 검증, 리팩토링을 제공할 수 있습니다. 이에는 다른 부수적인 장점도 있습니다. 이름 대신 어노테이션을 통해 객체, 이벤트, 인터셉터를 인식하고자 할 경우 이것이 나타나 코드의 시맨틱 레벨을 해제할 수 있습니다.
Web Beans는 개념을 모델로 하는 어노테이션을 개발하게 합니다. 예:
@Asynchronous
,
@Mock
,
@Secure
또는
@Updated
,
다음과 같은 복합적인 명칭을 사용하는 대신
asyncPaymentProcessor
,
mockPaymentProcessor
,
SecurityInterceptor
또는
DocumentUpdatedEvent
.
어노테이션은 다시 사용할 수 있습니다. 이는 시스템의 연관 없는 부분의 일반적인 기능을 설명하는데 사용되며, 코드를 이해하고 범주화하는데 사용될 수 있습니다. 이는 일반적인 문제를 일반적인 방식으로 해결하는데 도움을 주며, 코드를 보다 더 이해하고 읽고 쓸 수 있게 합니다.
Web Beans의 전형적인 역할은 이러한 기능에 한 단계 더 나아갑니다. 전형적인 역할은 애플리케이션 구조에서의 일반적인 역할을 모델로 합니다. 이는 범위, 인터셉터 바인딩, 배치 유형 등과 같은 다양한 역할의 속성으로 다시 사용 가능한 단일 패키지로 캡슐화합니다.
심지어 Web Beans XML 메타데이터는 강하게 타이핑됩니다! XML 용 컴파일러가 없으므로 Web Beans는 XML 스키마의 장점을 취해 XML에 나타나는 Java 유형 및 속성을 유효하게 합니다. 어노테이션이 Java 코드를 읽고 쓸 수 있게 하는 것 처럼 이러한 접근은 XML을 보다 더 읽고 쓸 수 있게 합니다.
이제 Web Beans의 보다 고급 기능에 대해 알아볼 준비가 되었습니다. 이러한 기능은 코드를 보다 쉽게 유효화하고 이해 가능하게 하기 위해 존재하는 것임을 명심하시기 바랍니다. 대부분 이러한 기능을 사용할 필요가 없지만 이를 보다 효과적으로 사용할 경우, 이러한 기능에 감사하게 될 것입니다.
Web Beans 사양에 따라:
여러 시스템에서, 아키텍처 패턴을 사용하여 Web Bean 역할을 반복하는 모음을 생산합니다. 스테레오타입은 프레임워크 개발자가 이러한 역할을 인식하고 중앙 위치에서의 역할과 함께 Web Beans의 일반적인 메타데이터를 명시하게 합니다.
스테레오타입은 다음의 조합을 캡슐화합니다:
기본값 배치 유형
기본값 범위 유형
Web Bean 범위에서의 제한,
특정 유형을 Web Bean이 구현하거나 확장하기 위한 요구 사항
인터셉터 바인딩 어노테이션 모음
스테레오타입은 스테레오타입이 있는 모든 Web Beans이 Web Bean 이름을 기본값으로 하도록 지정할 수 도 있습니다.
Web Bean은 0 또는 하나 이상의 스테레오타입을 명시할 있습니다.
스테레오타입은 Java 어노테이션 유형입니다. 이러한 스테레오타입은 일부 MVC 프레임워크에서 작업 클래스를 인식합니다:
@Retention(RUNTIME)
@Target(TYPE)
@Stereotype
public @interface Action {}
Web Bean에 어노테이션을 적용하여 스테레오타입을 사용합니다.
@Action
public class LoginAction { ... }
스테레오타입은 해당 스테레오타입과 함께 Web Beans의 기본값 범위 또는 기본값 배치 유형을 지정할 수 있습니다. 예를 들어, @WebTier
배치 유형이 시스템이 웹 애플리케이션으로 실행될 때만 Web Beans이 배치됨을 인식할 경우, 각각의 작업 클래스에 대해 다음과 같은 기본값을 지정할 수 있습니다:
@Retention(RUNTIME)
@Target(TYPE)
@RequestScoped
@WebTier
@Stereotype
public @interface Action {}
물론 특정 작업은 필요할 경우 이러한 기본값을 덮어쓰기할 수 있습니다:
@Dependent @Mock @Action
public class MockLoginAction { ... }
모든 작업을 특정 범위로 강제시키고자 할 경우, 강제시킬 수 있습니다.
어떤 작업이 특정 범위를 명시하지 못하게 하길 원한다고 가정합니다. Web Beans는 특정 스테레오타입과 함께 Web Beans의 허용 범위 모음을 명시적으로 지정할 수 있게 합니다. 예:
@Retention(RUNTIME)
@Target(TYPE)
@RequestScoped
@WebTier
@Stereotype(supportedScopes=RequestScoped.class)
public @interface Action {}
특정 작업 클래스가 Web Beans 요청 범위 외의 범위를 지정하려고 할 경우, 초기화시 예외 처리가 Web Bean 관리자에 의해 넘어가게 됩니다.
특정 스테레오타입과 함께 모든 Web Bean을 강제하여 인터페이스를 구현하거나 클래스를 확장할 수 있습니다:
@Retention(RUNTIME)
@Target(TYPE)
@RequestScoped
@WebTier
@Stereotype(requiredTypes=AbstractAction.class)
public @interface Action {}
특정 작업 클래스가 AbstractAction
클래스를 확장하지 않을 경우, 초기화시 예외 처리가 Web Bean 관리자에 의해 넘어가게 됩니다.
스테레오타입은 스테레오타입과 함께 모든 Web Beans에 의해 상속되기 위해 인터셉터 바인딩 모음을 지정할 수 있습니다.
@Retention(RUNTIME)
@Target(TYPE)
@RequestScoped
@Transactional(requiresNew=true)
@Secure
@WebTier
@Stereotype
public @interface Action {}
이는 비지니스 코드에서 발생할 수 있는 기술적 문제를 발생하지 않게 합니다!
마지막으로 특정 스테레오타입과 함께 모든 Web Beans가 Web Bean 관리자에 의해 기본값으된 Web Bean 이름을 갖도록 지정할 수 있습니다. 작업은 JSP 페이지에서 참조할 수 있어, 이러한 기능을 완벽하게 사용할 수 있는 경우라 할 수 있습니다. 필요한 작업은 빈 @Named
어노테이션을 추가하는 것입니다:
@Retention(RUNTIME)
@Target(TYPE)
@RequestScoped
@Transactional(requiresNew=true)
@Secure
@Named
@WebTier
@Stereotype
public @interface Action {}
이제 LoginAction
은 loginAction
이라는 이름을 갖게 됩니다.
Web Beans 사양에 의해 정의된 두가지 표준 스테레오타입 @Interceptor
및 @Decorator
를 살펴보았습니다.
Web Beans는 하나 이상의 표준 스테레오타입을 정의합니다:
@Named
@RequestScoped
@Stereotype
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface Model {}
이러한 스테레오타입은 JSF와 함께 사용하기 위한 것입니다. JSF 관리 beans을 사용하지 않고 Web Bean @Model
을 어노테이션하여 이를 직접 JSF 페이지에서 사용합니다.
이미 Web Beans 의존성 삽입 모델은 배치시 API 구현을 덮어쓰기 하게 합니다. 예를 들어, 다음과 같은 엔터프라이즈 Web Bean은 제품에서 API PaymentProcessor
구현을 제공합니다:
@CreditCard @Stateless
public class CreditCardPaymentProcessor
implements PaymentProcessor {
...
}
staging 환경에서, 다른 Web Bean을 사용하여 PaymentProcessor
구현을 덮어쓰기 합니다:
@CreditCard @Stateless @Staging
public class StagingCreditCardPaymentProcessor
implements PaymentProcessor {
...
}
StagingCreditCardPaymentProcessor
를 사용하여 실행하려는 작업은 특정 시스템 배치에 AsyncPaymentProcessor
를 완전 교체하는 것입니다. 여기서 배치 유형 @Staging
은 기본값 배치 유형 @Production
보다 높은 우선 순위를 갖게 되므로 클라이언트는 다음과 같은 삽입 지점을 사용하게 됩니다:
@CreditCard PaymentProcessor ccpp
StagingCreditCardPaymentProcessor
인스턴스를 받고자 합니다.
불행하게도 여기에는 몇 가지 함정이 있습니다:
높은 우선 순위의 Web Bean은 덮어쓰기하려는 Web Bean의 모든 API 유형을 구현할 수 없습니다.
높은 우선 순위의 Web Bean은 덮어쓰기하려는 Web Bean의 모든 바인딩 유형을 명시할 수 없습니다.
높은 우선 순위의 Web Bean은 덮어 쓰기하려는 Web Bean과 동일한 이름을 갖을 수 없습니다.
덮어쓰기하려는 Web Bean은 생산자 방식, 폐지 방식 또는 옵저버 방식을 명시할 수 있습니다.
이러한 경우, 덮어 쓰기하려는 Web Bean은 런타임시 호출 가능해야 합니다 따라서, 덮어쓰기는 다소 개발자 오류를 초래하는 경우가 있습니다.
Web Beans는 특성화라는 특별 기능을 제공하여, 개발자들이 이러한 함정에 빠지지 않도록 돕습니다. 특성화 기능은 처음에는 조금 난해하게 보이지만, 익숙해 지면 사용하기 쉬우며 제공되는 추가 보안 기능에 만족하실 것입니다.
특성화는 심플 Web Beans 및 엔터프라이즈 Web Beans에만 있는 기능입니다. 특성화 기능을 사용하려면 높은 우선 순위의 Web Bean은 다음 사항을 따라야 합니다:
덮어쓰기할 Web Bean의 직접적인 하부 클래스가 되어야 합니다.
덮어쓰기할 Web Bean이 심플 Web Bean일 경우 심플 Web Bean이 되어야 하고 또는 덮어쓰기 할 Web Bean이 엔터프라이즈 Web Bean일 경우 엔터프라이즈 Web Bean이 되어야 합니다
@Specializes
로 어노테이션되어야 합니다.
@Stateless @Staging @Specializes
public class StagingCreditCardPaymentProcessor
extends CreditCardPaymentProcessor {
...
}
높은 우선 순위의 Web Bean이 해당 상위클래스를 특성화한다고 합니다.
특성화 기능 사용시:
상위클래스의 바인딩 유형은 @Specializes
로 어노테이션된 Web Bean에 의해 자동으로 상속됩니다
상위클래스의 Web Bean 이름은 @Specializes
로 어노테이션된 Web Bean에 의해 자동으로 상속됩니다
상위클래스에 의해 명시된 생산자 방식, 폐지 방식 및 옵저버 방식은 @Specializes
로 어노테이션된 Web Bean 인스턴스를 호출합니다.
예에서 CreditCardPaymentProcessor
의 @CreditCard
바인딩 유형은 StagingCreditCardPaymentProcessor
에 의해 전승됩니다.
Web Bean 관리자는 다음 사항을 유효화합니다:
상위클래스의 모든 API 유형은 @Specializes
로 어노테이션된 Web Bean의 API 유형입니다 (상위클래스 엔터프라이즈 빈의 모든 로컬 인터페이스는 하부클래스의 로컬 인터페이스도 됩니다)
@Specializes
로 어노테이션된 Web Bean의 배치 유형은 상위클래스의 배치 유형보다 높은 우선 순위를 갖습니다
상위클래스를 특성화하는 활성화된 Web Bean이 없습니다.
이러한 조건을 위반할 경우, Web Bean 관리자는 초기화시 예외 처리를 넘기게 됩니다.
따라서, @Specializes
라고 어노테이션된 Web Bean이 배치되어 활성화된 시스템의 어떤 배치에서도 상위클래스는 절대로 호출되지 않음을 확인할 수 있습니다.
지금까지 어노테이션을 사용하여 명시된 여러 가지 Web Beans의 예를 살펴보았습니다. 하지만 Web Bean을 정의하기 위해 어노테이션을 사용할 수 없는 경우가 종종 있습니다:
구현 클래스가 일부 기존 라이브러에서 비롯되었을 경우,
동일한 구현 클래스를 갖는 다수의 Web Beans이 있을 경우
이러한 경우, Web Beans는 두 가지 옵션을 제공합니다:
생산자 방식 작성 또는
XML을 사용하여 Web Bean 명시
다수의 프레임워크는 XML을 사용하여 Java 클래스 관련 메타테이터를 제공합니다. 하지만, Web Beans는 다양한 접근 방법을 사용하여 Java 클래스 이름, 영역, 방식을 대부분의 다른 프레임워크에 지정합니다. XML 요소 및 속성의 문자열 값으로 클래스 및 멤버 이름을 작성하는 대신, Web Beans는 XML 요소 이름으로 클래스 또는 멤버 이름을 사용하게 합니다.
이러한 접근 방법의 장점은 XML 문서에서 스펠링 오류가 나타나지 않게 하는 XML 스키마를 작성할 수 있다는 것입니다. 컴파일된 Java 코드에서 XML 스키마를 자동으로 생성하기 위한 도구를 만들 수 도 있습니다. 또는 통합된 개발 환경은 중간 생성 단계를 거치지 않고 동일한 검증을 실행할 수 있습니다.
각각의 Java 패키지의 경우, Web Beans는 해당 XML namespace를 지정합니다. namespace는 Java 패키지 이름에 urn:java:
를 덧붙이기하여 형성됩니다. com.mydomain.myapp
패키지의 경우, XML namespace는 urn:java:com.mydomain.myapp
입니다.
패키지에 속한 Java 유형은 패키지에 해당하는 namespace에 있는 XML 요소를 사용하여 참조합니다. 요소 이름은 Java 유형의 이름이 됩니다. 유형 영역 및 방식은 동일한 namespace에 있는 자식 요소에 의해 지정됩니다. 유형이 어노테이션되어 있을 경우, 멤버는 요소의 속성에 의해 지정됩니다.
예를 들어, 다음의 XML 부분에 있는 <util:Date/>
요소는 java.util.Date
클래스를 참조합니다:
<WebBeans xmlns="urn:java:javax.webbeans"
xmlns:util="urn:java:java.util">
<util:Date/>
</WebBeans
>
Date
는 심플 Web Bean임을 명시해야 할 모든 코드입니다! Date
의 인스턴스는 기타 다른 Web Bean에 의해 삽입될 수 있습니다:
@Current Date date
Web Bean 명시의 직접적인 자식 요소를 사용하여 범위, 배치 유형, 인터셉터 바인딩 유형을 명시할 수 있습니다:
<myapp:ShoppingCart>
<SessionScoped/>
<myfwk:Transactional requiresNew="true"/>
<myfwk:Secure/>
</myapp:ShoppingCart
>
이름 및 바인딩 유형을 지정하기 위해 동일한 방법을 사용합니다:
<util:Date>
<Named
>currentTime</Named>
</util:Date>
<util:Date>
<SessionScoped/>
<myapp:Login/>
<Named
>loginTime</Named>
</util:Date>
<util:Date>
<ApplicationScoped/>
<myapp:SystemStart/>
<Named
>systemStartTime</Named>
</util:Date
>
여기서 @Login
및 @SystemStart
는 바인딩 어노테이션 유형입니다.
@Current Date currentTime;
@Login Date loginTime;
@SystemStart Date systemStartTime;
일반적으로 Web Bean은 여러 바인딩 유형을 지원할 수 있습니다:
<myapp:AsynchronousChequePaymentProcessor>
<myapp:PayByCheque/>
<myapp:Asynchronous/>
</myapp:AsynchronousChequePaymentProcessor
>
인터셉터 및 데코레이터는 심플 Web Beans이므로, 기타 다른 심플 Web Bean같이 나타낼 수 있습니다:
<myfwk:TransactionInterceptor>
<Interceptor/>
<myfwk:Transactional/>
</myfwk:TransactionInterceptor
>
Web Beans는 삽입 지점에서 Web Bean을 지정할 수 있게 합니다. 예:
<myapp:System>
<ApplicationScoped/>
<myapp:admin>
<myapp:Name>
<myapp:firstname
>Gavin</myapp:firstname>
<myapp:lastname
>King</myapp:lastname>
<myapp:email
>gavin@hibernate.org</myapp:email>
</myapp:Name>
</myapp:admin>
</myapp:System
>
<Name>
요소는 초기화 영역값 설정과 함께 @Dependent
범위의 심플 Web Bean 및 Name
클래스를 명시합니다. Web Bean은 특정한 컨테이너 생성 바인딩이 있으므로 명시된 특정 삽입 지점에만 삽입할 수 있습니다.
이러한 간단하지만 강력한 기능은 Web Beans XML 포맷이 Java 객체의 전체 그래프를 지정하는데 사용하게 합니다. 이는 완전한 데이터바인딩 솔루션이 아니지만, 근접한 솔루션입니다!
Java 개발자 이외나 또는 코드로 액세스할 수 없는 사람들에 의해 작성된 XML 문서 형식을 원하실 경우, 스키마를 제공해야 합니다. 스키마를 사용 또는 작성에 관해 Web Beans에 특정한 사항이 없습니다.
<WebBeans xmlns="urn:java:javax.webbeans"
xmlns:myapp="urn:java:com.mydomain.myapp"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:java:javax.webbeans http://java.sun.com/jee/web-beans-1.0.xsd
urn:java:com.mydomain.myapp http://mydomain.com/xsd/myapp-1.2.xsd">
<myapp:System>
...
</myapp:System>
</WebBeans
>
XML 스키마 작성은 다소 장황합니다. 따라서 Web Beans RI 프로젝트는 컴파일된 자바 코드에서 XML 스키마를 자동으로 생성하는 도구를 제공하게 됩니다.
Web Beans의 세 번째 기능은 통합 기능입니다. Web Beans는 다른 기술과 일제히 작동하도록 고안되어, 애플리케이션 개발자가 다른 기술을 함께 사용하게 합니다. 이는 Java EE 에코시스템의 일부분을 형성하여 새로운 에코시스템에 대해 기존 프레임워크와 기술로의 기능 통합 및 휴대용 확장의 기초가 됩니다.
EJB가 JSF 페이지에 직접 바운딩되게 하여 Web Beans이 어떻게 EJB 및 JSF를 통합하였는지를 살펴보았습니다. 이는 단지 시작에 불과합니다. Web Beans는 비지니스 프로세스 관리 엔진, 기타 다른 웹 프레임워크, 제삼자 구성 요소 모델과 같은 다른 기술을 다양화하기 위해 동일한 잠재적 기능을 제공합니다. Java EE 플랫폼은 Java 애플리케이션 개발에 사용되는 모든 기술을 표준화할 수 없지만, Web Beans는 Java EE 환경 내에 있는 플랫폼의 일부분에 속하지 않는 기술을 보다 쉽게 사용할 수 있게 합니다.
Web Beans을 사용하는 애플리케이션에서 Java EE 플랫폼의 장점을 최대한으로 활용하는 방법에 대해 살펴보겠습니다. 또한 Web Beans에 휴대용 확장을 지원하기 위해 제공되는 SPI 설정에 대해서도 간략하게 살펴보겠습니다. 이러한 SPI 기능을 직접 사용할 필요가 없을 수 도 있지만, 만약 필요할 경우 이러한 기능한 기능이 있다는 것을 알아두시면 좋습니다. 가장 중요하게 제삼자 확장 기능을 사용할 때 마다 이러한 기능의 장점을 간접적으로 활용할 수 있습니다.
Web Beans는 Java EE 환경으로 완전 통합됩니다. Web Beans는 Java EE 리소스 및 JPA 지속성 컨텍스트로 액세스합니다. 이는 JSF 및 JSP 페이지에서 Unified EL 표현식으로 사용될 수 있습니다. 이는 Web Beans가 아닌 Servlets 및 Message-Driven Beans와 같은 일부 객체로 삽입될 수 도 있습니다.
모든 엔터프라이즈 Web Beans는 @Resource
, @EJB
, @PersistenceContext
를 사용하여 Java EE 의존성 삽입의 장점을 취할 수 있습니다. 이미 이에 대한 몇몇 예를 살펴보았습니다:
@Transactional @Interceptor
public class TransactionInterceptor {
@Resource Transaction transaction;
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
@SessionScoped
public class Login {
@Current Credentials credentials;
@PersistenceContext EntityManager userDatabase;
...
}
Java EE @PostConstruct
및 @PreDestroy
콜백은 모든 엔터프라이즈 Web Beans에 대해 지원됩니다. 모든 삽입이 실행된 후 @PostConstruct
방식이 호출됩니다.
여기서 유의해야 할 한 가지 제한 사항이 있습니다: @PersistenceContext(type=EXTENDED)
는 단순한 Web Beans에 대해 지원되지 않습니다.
Java EE 6에 있는 Servlet에서 Web Bean을 사용하기가 쉽습니다. Web Beans 영역 또는 초기화 방식 삽입을 사용하여 Web Bean을 삽입합니다.
public class Login extends HttpServlet {
@Current Credentials credentials;
@Current Login login;
@Override
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
credentials.setUsername( request.getAttribute("username") ):
credentials.setPassword( request.getAttribute("password") ):
login.login();
if ( login.isLoggedIn() ) {
response.sendRedirect("/home.jsp");
}
else {
response.sendRedirect("/loginError.jsp");
}
}
}
Web Beans 클라이언트 프록시는 Servlet에서 현재 요청 및 메소드 HTTP 세션의 올바른 Credentials
및 Login
인스턴스로 호출을 라우팅을 처리합니다.
Web Beans 삽입은 모든 EJB에 적용되며, Web Bean 관리자 제어 하에 있지 않을 경우에도 (예들 들어, JNDI lookup에 의해 획득되었거나 @EJB
를 사용하여 삽입되었을 경우) 적용됩니다. 특히, Message-Driven Beans에서 Web Beans 삽입을 사용할 수 있으며, 이를 삽입할 수 없기 때문에 이는 Web Beans를 고려하지 않습니다.
Message-Driven Beans에 대한 Web Beans 인터셉터 바인딩을 사용할 수 있습니다.
@Transactional @MessageDriven
public class ProcessOrder implements MessageListener {
@Current Inventory inventory;
@PersistenceContext EntityManager em;
public void onMessage(Message message) {
...
}
}
따라서, Web Beans 환경에서 메세지를 받는 것은 초간편합니다. 하지만 메세지가 Message-Driven Bean으로 전달될 때 사용할 수 있는 세션 또는 대화 컨텍스트가 없음에 유의하시기 바랍니다. @RequestScoped
및 @ApplicationScoped
Web Beans 만을 사용할 수 있습니다.
또한 Web Beans를 사용하여 메세지를 전송하기 쉽습니다.
JMS를 사용하여 메세지를 전송하는 것은 다소 복잡할 수 있습니다. 이는 다수의 다른 개체를 처리해야 하기 때문입니다. 큐의 경우 Queue
, QueueConnectionFactory
, QueueConnection
, QueueSession
QueueSender
를 갖습니다. 토픽의 경우 Topic
, TopicConnectionFactory
, TopicConnection
, TopicSession
, TopicPublisher
를 갖습니다. 이러한 각각의 객체는 자체적으로 수명 주기 및 스레딩 모델을 갖고 있습니다.
Web Beans는 이러한 모든 것을 처리합니다. 여기서 처리해야 할 사항은 web-beans.xml
에 있는 큐 또는 토픽을 명명하고 관련된 바인딩 유형 및 연결 팩토리를 지정하는 것입니다.
<Queue>
<destination
>java:comp/env/jms/OrderQueue</destination>
<connectionFactory
>java:comp/env/jms/QueueConnectionFactory</connectionFactory>
<myapp:OrderProcessor/>
</Queue
>
<Topic>
<destination
>java:comp/env/jms/StockPrices</destination>
<connectionFactory
>java:comp/env/jms/TopicConnectionFactory</connectionFactory>
<myapp:StockPrices/>
</Topic
>
이제 큐의 경우 Queue
, QueueConnection
, QueueSession
, QueueSender
를 삽입할 수 있고, 토픽의 경우 Topic
, TopicConnection
, TopicSession
TopicPublisher
를 삽입할 수 있습니다.
@OrderProcessor QueueSender orderSender;
@OrderProcessor QueueSession orderSession;
public void sendMessage() {
MapMessage msg = orderSession.createMapMessage();
...
orderSender.send(msg);
}
@StockPrices TopicPublisher pricePublisher;
@StockPrices TopicSession priceSession;
public void sendMessage(String price) {
pricePublisher.send( priceSession.createTextMessage(price) );
}
삽입된 JMS 객체의 수명주기는 Web Bean 관리자에 의해 전적으로 관리됩니다.
Web Beans는 특정 배포 아카이브를 지정하지 않습니다. JAR, EJB-JAR 또는 WAR에 있는 Web Beans 애플리케이션 classpath에 있는 배포 위치를 패키지화할 수 있습니다. 하지만 Web Beans이 있는 각각의 아카이브에는 META-INF
또는 WEB-INF
디렉토리에 있는 web-beans.xml
라는 파일이 들어 있어야 합니다. 파일은 비어 있을 수 도 있습니다. web-beans.xml
파일이 없는 아카이브에 배포된 Web Beans는 애플리케이션에서 사용할 수 없습니다.
Java SE 실행의 경우, 임베드 가능한 EJB Lite 컨테이너에 의해 실행용 EJB를 배포할 수 있는 위치에 Web Beans를 배포할 수 있습니다. 각 위치에서는 web-beans.xml
파일이 들어 있어야 합니다.
Web Beans는 다른 기술과의 통합, 확장, 프레임워크에 대한 플랫폼이 되기 위한 것입니다. 따라서, Web Beans는 Web Beans로의 휴대용 확장에 대한 개발자의 사용을 위해 SPI 모음을 노출합니다. 예를 들어, 다음과 같은 종류의 확장은 Web Beans 개발자에 의해 구상되었습니다.
비지니스 프로세스 관리 엔진과의 통합
Spring, Seam, GWT, Wicket과 같은 제삼자 프레임워크와의 통합
Web Beans 프로그래밍 모델을 기반으로 하는 새로운 기술
Web Beans 확장의 중심은 Manager
객체입니다.
Manager
인터페이스는 Web Beans, 인터셉터, 데코레이터, 옵저버 및 컨텍스트를 프로그램적으로 획득하여 등록할 수 있게 합니다.
public interface Manager
{
public <T
> Set<Bean<T
>
> resolveByType(Class<T
> type, Annotation... bindings);
public <T
> Set<Bean<T
>
> resolveByType(TypeLiteral<T
> apiType,
Annotation... bindings);
public <T
> T getInstanceByType(Class<T
> type, Annotation... bindings);
public <T
> T getInstanceByType(TypeLiteral<T
> type,
Annotation... bindings);
public Set<Bean<?>
> resolveByName(String name);
public Object getInstanceByName(String name);
public <T
> T getInstance(Bean<T
> bean);
public void fireEvent(Object event, Annotation... bindings);
public Context getContext(Class<? extends Annotation
> scopeType);
public Manager addContext(Context context);
public Manager addBean(Bean<?> bean);
public Manager addInterceptor(Interceptor interceptor);
public Manager addDecorator(Decorator decorator);
public <T
> Manager addObserver(Observer<T
> observer, Class<T
> eventType,
Annotation... bindings);
public <T
> Manager addObserver(Observer<T
> observer, TypeLiteral<T
> eventType,
Annotation... bindings);
public <T
> Manager removeObserver(Observer<T
> observer, Class<T
> eventType,
Annotation... bindings);
public <T
> Manager removeObserver(Observer<T
> observer,
TypeLiteral<T
> eventType, Annotation... bindings);
public <T
> Set<Observer<T
>
> resolveObservers(T event, Annotation... bindings);
public List<Interceptor
> resolveInterceptors(InterceptionType type,
Annotation... interceptorBindings);
public List<Decorator
> resolveDecorators(Set<Class<?>
> types,
Annotation... bindings);
}
삽입을 통해 Manager
인스턴스를 얻을 수 있습니다:
@Current Manager manager
Bean
추상 클래스의 인스턴스는 Web Beans를 나타냅니다. 애플리케이션에 있는 모든 Web Bean에 해당하는 Manager
객체로 등록된 Bean
인스턴스가 있습니다.
public abstract class Bean<T> {
private final Manager manager;
protected Bean(Manager manager) {
this.manager=manager;
}
protected Manager getManager() {
return manager;
}
public abstract Set<Class> getTypes();
public abstract Set<Annotation> getBindingTypes();
public abstract Class<? extends Annotation> getScopeType();
public abstract Class<? extends Annotation> getDeploymentType();
public abstract String getName();
public abstract boolean isSerializable();
public abstract boolean isNullable();
public abstract T create();
public abstract void destroy(T instance);
}
Web Beans 사양 (심플 Web Beans 및 엔터프라이즈 Web Beans, 생산자 방식 및 JMS 엔드포인트)에 의해 정의된 것 이상으로 새로운 종류의 Web Beans을 지원하기 위해 Bean
클래스를 확장하고 Manager.addBean()
를 호출하여 인스턴스를 등록할 수 있습니다. 예를 들어, Bean
클래스를 사용하여 Web Beans에 주입된 다른 프레임워크에 의해 관리되는 객체를 허용하게 할 수 있습니다.
Web Beans 사양에 의해 정의되는 두 개의 Bean
하부 클래스가 있습니다: Interceptor
및 Decorator
.
Context
인터페이스는 Web Beans에 새로운 범위를 추가로 지원하거나 새로운 환경에 내장된 범위를 확장 지원합니다.
public interface Context {
public Class<? extends Annotation> getScopeType();
public <T> T get(Bean<T> bean, boolean create);
boolean isActive();
}
예를 들어, Web Beans에 비지니스 프로세스 범위를 추가하거나 또는 Wicket을 사용하는 애플리케이션에 컨버세이션 범위에 대한 지원을 추가하기 위해 Context
를 구현할 수 있습니다.
Web Beans는 새로운 기능이기 때문에 아직 온라인에서 사용 가능한 정보가 많지 않습니다.
Web Beans 사양은 자세한 Web Beans 정보가 있는 최고의 소스입니다. 이는 약 100 페이지로 된 이 문서의 두 배 길이로 대부분 읽을 수 있습니다. 이는 여기서 생략된 내용을 자세하게 다루고 있으며, http://jcp.org/en/jsr/detail?id=299
에서 보실 수 있습니다.
Web Beans Reference 구현은 http://seamframework.org/WebBeans
에서 개발되고 있습니다. RI 개발팀 및 Web Beans 사양은 http://in.relation.to
에 있는 블로그에 있습니다. 이러한 문서는 실질적으로 블로그에 게시된 기사의 시리즈를 기반으로 합니다.
Web Beans is the reference implementation of JSR-299, and is used by JBoss AS and Glassfish to provide JSR-299 services for Java Enterprise Edition applications. Web Beans also goes beyond the environments and APIs defined by the JSR-299 specification and provides support for a number of other environments (such as a servlet container such as Tomcat, or Java SE) and additional APIs and modules (such as logging, XSD generation for the JSR-299 XML deployment descriptors).
If you want to get started quickly using Web Beans with JBoss AS or Tomcat and experiment with one of the examples, take a look at 3장. Web Beans, the Reference Implementation of JSR-299. Otherwise read on for a exhaustive discussion of using Web Beans in all the environments and application servers it supports, as well the Web Beans extensions.
No special configuration of your application, beyond adding either META-INF/beans.xml
or WEB-INF/beans.xml
is needed.
If you are using JBoss AS 5.0.1.GA then you'll need to install Web Beans as an extra. First we need to tell Web Beans where JBoss is located. Edit jboss-as/build.properties
and set the jboss.home
property. For example:
jboss.home=/Applications/jboss-5.0.1.GA
Now we can install Web Beans:
$ cd webbeans-$VERSION/jboss-as $ ant update
A new deployer, webbeans.deployer
is added to JBoss AS. This adds supports for JSR-299 deployments to JBoss AS, and allows Web Beans to query the EJB3 container and discover which EJBs are installed in your application.
Web Beans is built into all releases of JBoss AS from 5.1 onwards.
Web Beans can be used in Tomcat 6.0.
Web Beans doesn't support deploying session beans, injection using @EJB
, or @PersistenceContext
or using transactional events on Tomcat.
Web Beans should be used as a web application library in Tomcat. You should place webbeans-tomcat.jar
in WEB-INF/lib
. webbeans-tomcat.jar
is an "uber-jar" provided for your convenience. Instead, you could use its component jars:
jsr299-api.jar
webbeans-api.jar
webbeans-spi.jar
webbeans-core.jar
webbeans-logging.jar
webbeans-tomcat-int.jar
javassist.jar
dom4j.jar
You also need to explicitly specify the Tomcat servlet listener (used to boot Web Beans, and control its interaction with requests) in web.xml
:
<listener> <listener-class >org.jboss.webbeans.environment.servlet.Listener</listener-class> </listener >
Tomcat has a read-only JNDI, so Web Beans can't automatically bind the Manager. To bind the Manager into JNDI, you should add the following to your META-INF/context.xml
:
<Resource name="app/Manager" auth="Container" type="javax.inject.manager.Manager" factory="org.jboss.webbeans.resources.ManagerObjectFactory"/>
and make it available to your deployment by adding this to web.xml
:
<resource-env-ref> <resource-env-ref-name> app/Manager </resource-env-ref-name> <resource-env-ref-type> javax.inject.manager.Manager </resource-env-ref-type> </resource-env-ref>
Tomcat only allows you to bind entries to java:comp/env
, so the Manager will be available at java:comp/env/app/Manager
Web Beans also supports Servlet injection in Tomcat. To enable this, place the webbeans-tomcat-support.jar
in $TOMCAT_HOME/lib
, and add the following to your META-INF/context.xml
:
<Listener className="org.jboss.webbeans.environment.tomcat.WebBeansLifecycleListener" />
Apart from improved integration of the Enterprise Java stack, Web Beans also provides a state of the art typesafe, stateful dependency injection framework. This is useful in a wide range of application types, enterprise or otherwise. To facilitate this, Web Beans provides a simple means for executing in the Java Standard Edition environment independently of any Enterprise Edition features.
When executing in the SE environment the following features of Web Beans are available:
Simple Web Beans (POJOs)
Typesafe Dependency Injection
Application and Dependent Contexts
Binding Types
Stereotypes
Decorators
(TODO: Interceptors ?)
Typesafe Event Model
To make life easy for developers Web Beans provides a special module with a main method which will boot the Web Beans manager, automatically registering all simple Web Beans found on the classpath. This eliminates the need for application developers to write any bootstrapping code. The entry point for a Web Beans SE applications is a simple Web Bean which observes the standard @Deployed Manager
event. The command line paramters can be injected using either of the following:
@Parameters List<String
> params;
@Parameters String[] paramsArray; // useful for compatability with existing classes
Here's an example of a simple Web Beans SE application:
@ApplicationScoped
public class HelloWorld
{
@Parameters List<String
> parameters;
public void printHello( @Observes @Deployed Manager manager )
{
System.out.println( "Hello " + parameters.get(0) );
}
}
Web Beans SE applications are started by running the following main method.
java org.jboss.webbeans.environments.se.StartMain <args
>
If you need to do any custom initialization of the Web Beans manager, for example registering custom contexts or initializing resources for your beans you can do so in response to the @Initialized Manager
event. The following example registers a custom context:
public class PerformSetup
{
public void setup( @Observes @Initialized Manager manager )
{
manager.addContext( ThreadContext.INSTANCE );
}
}
The command line parameters do not become available for injection until the @Deployed Manager
event is fired. If you need access to the parameters during initialization you can do so via the public static String getParameters()
method in StartMain
.
These modules are usable on any JSR-299 implementation, not just Web Beans!
현재 Web Beans RI는 JBoss AS 5에서만 실행됩니다; RI를 기타 다른 EE 환경 (예를 들어 Glassfish와 같은 다른 애플리케이션 서버)으로 통합, 또는 servlet 컨테이너로 통합 (예: Tomcat), 또는 내장된 EJB3.1 구현과 통합하는 것은 쉽습니다. Appendix에서 필요한 절차에 대해 간략하게 살펴보겠습니다.
SE 환경에서 Web Beans를 실행할 수 있어야 하지만, 자체적 컨텍스트 및 수명 주기 추가와 같은 더 많은 작업을 해야 합니다. 현재 Web Beans RI는 수명 확장 지점을 나타내지 않고 있으므로, Web Beans RI 클래스에 대해 직접 코드화해야 합니다.
The Web Beans SPI is located in webbeans-spi
module, and packaged as webbeans-spi.jar
. Some SPIs are optional, if you need to override the default behavior, others are required.
SPI에 있는 모든 인터페이스는 데코레이터 패턴을 지원하고 Forwarding
클래스를 제공합니다.
public interface WebBeanDiscovery {
/**
* Gets list of all classes in classpath archives with web-beans.xml files
*
* @return An iterable over the classes
*/
public Iterable<Class<?>
> discoverWebBeanClasses();
/**
* Gets a list of all web-beans.xml files in the app classpath
*
* @return An iterable over the web-beans.xml files
*/
public Iterable<URL
> discoverWebBeansXml();
}
Web Bean 클래스 및 web-bean.xml
파일 검색은 쉽게 알 수 있습니다 (알고리즘은 JSR-299 사양 11.1장에 설명되어 있으므로 여기서 다시 설명하지 않습니다).
Web Beans RI는 컨테이너로 EJB3 bean 검색을 위임하므로 EJB3 어노테이션을 검색하거나 ejb-jar.xml
을 파싱할 필요가 없습니다. 애플리케이션에 있는 각각의 EJB의 경우 EJBDescriptor를 검색해야 합니다:
public interface EjbServices
{
/**
* Gets a descriptor for each EJB in the application
*
* @return The bean class to descriptor map
*/
public Iterable<EjbDescriptor<?>> discoverEjbs();
public interface EjbDescriptor<T
> {
/**
* Gets the EJB type
*
* @return The EJB Bean class
*/
public Class<T
> getType();
/**
* Gets the local business interfaces of the EJB
*
* @return An iterator over the local business interfaces
*/
public Iterable<BusinessInterfaceDescriptor<?>
> getLocalBusinessInterfaces();
/**
* Gets the remote business interfaces of the EJB
*
* @return An iterator over the remote business interfaces
*/
public Iterable<BusinessInterfaceDescriptor<?>
> getRemoteBusinessInterfaces();
/**
* Get the remove methods of the EJB
*
* @return An iterator over the remove methods
*/
public Iterable<Method
> getRemoveMethods();
/**
* Indicates if the bean is stateless
*
* @return True if stateless, false otherwise
*/
public boolean isStateless();
/**
* Indicates if the bean is a EJB 3.1 Singleton
*
* @return True if the bean is a singleton, false otherwise
*/
public boolean isSingleton();
/**
* Indicates if the EJB is stateful
*
* @return True if the bean is stateful, false otherwise
*/
public boolean isStateful();
/**
* Indicates if the EJB is and MDB
*
* @return True if the bean is an MDB, false otherwise
*/
public boolean isMessageDriven();
/**
* Gets the EJB name
*
* @return The name
*/
public String getEjbName();
}
EjbDescriptor
는 쉽게 알 수 있어야 하며 EJB 사양에 정의되어 있음으로 관련된 메타데이터를 반환해야 합니다. 이러한 두 가지 인터페이스에 더하여, 로컬 비지니스 인터페이스를 나타내는 BusinessInterfaceDescriptor
가 있습니다. (EJB 인스턴스를 검색하는데 사용되는 인터페이스 클래스 및 jndi 이름을 캡슐화)
The resolution of @EJB
and @Resource
is delegated to the container. You must provide an implementation of org.jboss.webbeans.ejb.spi.EjbServices
which provides these operations. Web Beans passes in the javax.inject.manager.InjectionPoint
the resolution is for, as well as the NamingContext
in use for each resolution request.
Just as resolution of @EJB
is delegated to the container, so is resolution of @PersistenceContext
.
OPEN ISSUE: Web Beans also requires the container to provide a list of entities in the deployment, so that they aren't discovered as simple beans.
The Web Beans RI must delegate JTA activities to the container. The SPI provides a couple hooks to easily achieve this with the TransactionServices
interface.
public interface TransactionServices
{
/**
* Possible status conditions for a transaction. This can be used by SPI
* providers to keep track for which status an observer is used.
*/
public static enum Status
{
ALL, SUCCESS, FAILURE
}
/**
* Registers a synchronization object with the currently executing
* transaction.
*
* @see javax.transaction.Synchronization
* @param synchronizedObserver
*/
public void registerSynchronization(Synchronization synchronizedObserver);
/**
* Queries the status of the current execution to see if a transaction is
* currently active.
*
* @return true if a transaction is active
*/
public boolean isTransactionActive();
}
The enumeration Status
is a convenience for implementors to be able to keep track of whether a synchronization is supposed to notify an observer only when the transaction is successful, or after a failure, or regardless of the status of the transaction.
Any javax.transaction.Synchronization
implementation may be passed to the registerSynchronization()
method and the SPI implementation should immediately register the synchronization with the JTA transaction manager used for the EJBs.
To make it easier to determine whether or not a transaction is currently active for the requesting thread, the isTransactionActive()
method can be used. The SPI implementation should query the same JTA transaction manager used for the EJBs.
Web Beans expects the Application Server or other container to provide the storage for each application's context. The org.jboss.webbeans.context.api.BeanStore
should be implemented to provide an application scoped storage. You may find org.jboss.webbeans.context.api.helpers.ConcurrentHashMapBeanStore
useful.
The org.jboss.webbeans.bootstrap.api.Bootstrap
interface defines the bootstrap for Web Beans. To boot Web Beans, you must obtain an instance of org.jboss.webbeans.bootstrap.WebBeansBootstrap
(which implements Boostrap
), tell it about the SPIs in use, and then request the container start.
The bootstrap is split into phases, bootstrap initialization and boot and shutdown. Initialization will create a manager, and add the standard (specification defined) contexts. Bootstrap will discover EJBs, classes and XML; add beans defined using annotations; add beans defined using XML; and validate all beans.
The bootstrap supports multiple environments. Different environments require different services to be present (for example servlet doesn't require transaction, EJB or JPA services). By default an EE environment is assumed, but you can adjust the environment by calling bootstrap.setEnvironment()
.
To initialize the bootstrap you call Bootstrap.initialize()
. Before calling initialize()
, you must register any services required by your environment. You can do this by calling bootstrap.getServices().add(JpaServices.class, new MyJpaServices())
. You must also provide the application context bean store.
Having called initialize()
, the Manager
can be obtained by calling Bootstrap.getManager()
.
To boot the container you call Bootstrap.boot()
.
To shutdown the container you call Bootstrap.shutdown()
. This allows the container to perform any cleanup operations needed.
The Web Beans RI implements JNDI binding and lookup according to standards, however you may want to alter the binding and lookup (for example in an environment where JNDI isn't available). To do this, implement org.jboss.webbeans.resources.spi.NamingContext
:
public interface NamingContext extends Serializable {
/**
* Typed JNDI lookup
*
* @param <T
> The type
* @param name The JNDI name
* @param expectedType The expected type
* @return The object
*/
public <T
> T lookup(String name, Class<? extends T
> expectedType);
/**
* Binds an item to JNDI
*
* @param name The key to bind under
* @param value The item to bind
*/
public void bind(String name, Object value);
}
Web Beans RI는 여러번 classpath에서 클래스 및 리소스를 불러와야 합니다. 기본값으로 RI를 불러오기 위해 사용되었던 동일한 classloader에서 로딩되지만, 일부 환경에서는 작동하지 않을 수 도 있습니다. 이러한 경우, org.jboss.webbeans.spi.ResourceLoader
를 구현할 수 있습니다:
public interface ResourceLoader {
/**
* Creates a class from a given FQCN
*
* @param name The name of the clsas
* @return The class
*/
public Class<?> classForName(String name);
/**
* Gets a resource as a URL by name
*
* @param name The name of the resource
* @return An URL to the resource
*/
public URL getResource(String name);
/**
* Gets resources as URLs by name
*
* @param name The name of the resource
* @return An iterable reference to the URLS
*/
public Iterable<URL
> getResources(String name);
}
Java EE / Servlet does not provide any hooks which can be used to provide injection into Servlets, so Web Beans provides an API to allow the container to request JSR-299 injection for a Servlet.
To be compliant with JSR-299, the container should request servlet injection for each newly instantiated servlet after the constructor returns and before the servlet is placed into service.
To perform injection on a servlet call WebBeansManager.injectServlet()
. The manager can be obtained from Bootstrap.getManager()
.
API의 외부 구현에서의 올바른 기능을 실행하게 하기 위해 Web Beans RI이 컨테이너에 위치하게 해야 할 여러 요구 사항이 있습니다
Web Beans RI를 다수의 애플리케이션의 운용을 지원하는 환경으로 통합할 경우, 각각의 Web Beans 애플리케이션에 대한 클래스로더 분리를 자동으로 또는 사용자 설정을 통해 반드시 활성화해야 합니다.
Web Beans를 Servlet 환경으로 통합할 경우, Servlet을 사용하는 각각의 Web Beans 애플리케이션에 대해 자동으로 또는 사용자 설정을 통해 org.jboss.webbeans.servlet.WebBeansListener
를 Servlet 청취자로 등록해야 합니다.
If you are integrating the Web Beans into a JSF environment you must register org.jboss.webbeans.servlet.ConversationPropagationFilter
as a Servlet listener, either automatically, or through user configuration, for each Web Beans application which uses JSF. This filter can be registered for all Servlet deployment safely.
Web Beans를 EJB 환경으로 통합하고자 할 경우 엔터프라이즈 beans를 사용하는 각각의 Web Beans 애플리케이션 용으로 모든 EJB 애플리케이션에 대해 EJB 인터셉터로서 org.jboss.webbeans.ejb.SessionBeanInterceptor
를 자동으로 또는 사용자 설정을 통해 등록해야 합니다.
You must register the SessionBeanInterceptor
as the inner most interceptor in the stack for all EJBs.
webbeans-core.jar
If you are integrating the Web Beans into an environment that supports deployment of applications, you must insert the webbeans-core.jar
into the applications isolated classloader. It cannot be loaded from a shared classloader.