SeamFramework.orgCommunity Documentation

7장. 인터셉터

7.1. 인터셉터 바인딩
7.2. 인터셉터 구현
7.3. 인터셉터 활성화
7.4. 멤버와 인터셉터 바인딩
7.5. 여러개의 인터셉터 바인딩 어노테이션
7.6. 인터셉터 바인딩 유형 상속
7.7. @Interceptors 사용

Web Beans는 EJB 3.0의 기본 인터셉터 구조를 재사용하여, 두 가지 방향으로 기능을 확장합니다:

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 값을 사용하여 두 개의 다른 인터셉터 TransactionInterceptorRequiresNewTransactionInterceptor 중에서 선택하게 됩니다.

@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에 TransactionInterceptorSecurityInterceptor를 바인딩할 수 있습니다:

@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은 TransactionInterceptorSecurityInterceptor로 바운딩됩니다. (TransactionalSecureInterceptor이 있을 경우 이것으로 바운딩됩니다.)

EJB 사양에 의해 정의된 @Interceptors 어노테이션은 엔터프라이즈 및 심플 Web Beans 모두를 지원합니다. 예:

@Interceptors({TransactionInterceptor.class, SecurityInterceptor.class})

public class ShoppingCart {
    public void checkout() { ... }
}

하지만, 이러한 방식은 다음과 같은 결점을 갖습니다:

따라서 Web Beans 형식 인터셉터 바인딩을 사용할 것을 권장합니다.