Spring 事务管理:使用@Transactional 与使用 AOP (<aop:advisor)

Spring Transaction Management: using @Transactional vs using AOP (<aop:advisor)

我对 Spring 事务管理感到困惑。在我的应用程序中,我在服务 class 中使用 @Transactional 实现了事务管理。我将 spring.xml 配置为:

    <beans:bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
            <beans:property name="dataSource" ref="dataSource" />
            <beans:property name="configLocation" value="classpath:hibernate.cfg.xml"/>                              
            <beans:property name="hibernateProperties">
                <beans:props>
                    <beans:prop key="hibernate.dialect">${jdbc.dialect}</beans:prop>
                    <beans:prop key="hibernate.show_sql">false</beans:prop>
                    <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
                </beans:props>
            </beans:property>
        </beans:bean>  
        <!-- Transaction manager -->
            <beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
                <beans:property name="sessionFactory" ref="sessionFactory" />
            </beans:bean> 

如果我像下面这样在配置文件中实现事务管理而不在服务中使用@Transactional class:

    <aop:pointcut id="defaultServiceOperation"
            expression="execution(* x.y.service.*Service.*(..))"/>

    <aop:pointcut id="noTxServiceOperation"
            expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>

    <aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>

    <aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>

</aop:config>

与@Transactional 相比,它能给我带来什么好处吗?有人告诉我使用@Transactional 也是spring 中AOP 的实现。谁能告诉我怎么做?

不会。

好处

如果您不需要一些非常具体的要求或者您没有性能问题,您不应该重新发明轮子。 Spring 近乎完美的设计、测试和利器,即使是企业应用服务器也可以替代。 @Transactional 是管理事务的声明方式,它比任何 aop xml 配置更方便和可读。它的好处包括以声明方式自动处理所有事务管理方面:隔离和传播级别(控制嵌套事务并不容易)、超时、回滚条件和服务的每个方法的不同 TransactionManagers class。易于阅读、易于配置、易于使用。

@Transactional(readOnly = false, rollbackFor = ServiceException.class, isolation = Isolation.READ_COMMITTED)
public void myServiceJob(...)

当您看到此方法时,很容易理解它的事务属性(无需在方法中提供事务实现细节)。在普通 AOP 的情况下,每次您想知道此方法中发生了什么,您应该检查您的 xml 配置并找到相应的方法,这不太优雅。

另一方面,很难调试或使用这些代理进行任何其他声明式管理。例如。从上下文中提取你的 bean 并使用反射从你包装的 bean 中获取一些东西是很棘手的(但并非不可能)(比方说,出于监控目的)。另外,当bean调用它的某个方法时,不会委托给proxy,因为你的bean对proxy一无所知,所以this指的是bean本身。解决这个问题的唯一方法是提供 "self" 字段并将其设置在自定义 bean 后处理器中(但您的实现也会受到影响)。

实施

如果 Spring 配置为使用事务管理,它会在 bean 的定义上寻找 @Transactional 注释并创建自动生成的 AOP 代理,它是 bean 的子class。 Spring 代理的默认行为只是将方法调用委托给底层 bean。然后 Spring 向 TransactionInterceptor 注入必要的 TransactionManagers。 拦截器代码看起来很简单:

public Object invoke(final MethodInvocation invocation) throws Throwable {
    // Work out the target class: may be {@code null}.
    // The TransactionAttributeSource should be passed the target class
    // as well as the method, which may be from an interface.
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

    // Adapt to TransactionAspectSupport's invokeWithinTransaction...
    return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
        @Override
        public Object proceedWithInvocation() throws Throwable {
            return invocation.proceed();
        }
    });
}

invokeWithinTransaction 内部 TransactionInterceptor 决定调用是在调用者事务范围内(如果存在)还是在新事务范围内(与传播级别有关)。然后选择相应的TransactionManager,配置超时和隔离级别,然后调用该方法。在它决定是否应该提交或回滚事务之后(根据捕获的异常和时间做出选择)。