关于CDI拦截器绑定的更多内容

作者:    |       CDI

回复此文章Matt写道:

我在这里仍然有一些困扰,如果我们为六个EJBTransactionAttributeType实现分别的拦截器和绑定,并将它们打包在一个.jar文件中...我在beans.xml文件中为我的.war文件设置一些启用功能是可以的,但要求用户输入所有六个拦截器对于库开发人员来说比较麻烦...

经过几个小时我差点就认同了他的观点,但后来发现CDI有一个相当不错的解决方案。

Matt试图为每种事务传播风格创建不同的注解,例如@RequiresTransaction, @RequiresNewTransaction, @MandatoryTransaction等,而不是使用一个单一的@Transactional注解,该注解使用注解成员来指定传播风格。他担心CDI会强制他使用每个注解的单独拦截器,然后在文件中为我的.

中声明所有这些拦截器类。但有一个更好的方法::-)

首先,让我们创建一个拦截器绑定类型,该类型使用成员指定传播风格。请注意,我们不会直接在我们的Bean中使用这个。

@Inherited 
@InterceptorBinding 
@Target({TYPE, METHOD}) 
@Retention(RUNTIME) 
public @interface Transactional {
    @Nonbinding
    TransactionPropagation value() default REQUIRED;
}

其中TransactionPropagation是一个传播风格的枚举

public enum TransactionPropagation { REQUIRED, REQUIRES_NEW, MANDATORY, ... }

CDI拦截器绑定可以被其他拦截器绑定继承。此功能允许我们将我们的@Transactional注解作为元注解使用。所以让我们将@Transactional应用到Matt的注解上,例如

@Inherited 
@Transactional(REQUIRED)
@InterceptorBinding 
@Target({TYPE, METHOD}) 
@Retention(RUNTIME) 
public @interface RequiresTransaction {}
@Inherited
@Transactional(REQUIRES_NEW)
@InterceptorBinding 
@Target({TYPE, METHOD}) 
@Retention(RUNTIME) 
public @interface RequiresNewTransaction {}

我们通过注解Bean类来使用这些拦截器绑定,例如

@RequiresTransaction
public class Users {
    @RequiresNewTransaction
    public void login() { ... }
}

方法级别的注解应该覆盖类级别的注解。

现在我们可以使用单个拦截器类来实现事务管理

@Transactional @Interceptor
class TransactionInterceptor {

    @AroundInvoke
    public Object manageTransaction(InvocationContext ctx) throws Exception {
        TransactionPropagation tp = getTransactionPropagation(ctx.getMethod());
        ...
    }
    
    /**
     * Get the TransactionPropagation for the meta-annotation
     */
    private TransactionPropagation getTransactionPropagation(Method m) {
        //first look at method-level annotations, since they take priority
        for (Annotation a: m.getAnnotations()) {
            if (a.annotationType().isAnnotationPresent(Transactional.class)) {
                return a.annotationType().getAnnotation(Transactional.class).value();
            }
        }
        //now try class-level annotations
        for (Annotation a: m.getDeclaringClass().getAnnotations()) {
            if (a.annotationType().isAnnotationPresent(Transactional.class)) {
                return a.annotationType().getAnnotation(Transactional.class).value();
            }
        }
        return null;
    }
    
}

这个实现所有事务传播风格的拦截器类。很酷,不是吗?


回到顶部