SeamFramework.orgCommunity Documentation
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 형식 인터셉터 바인딩을 사용할 것을 권장합니다.