Spring Transaction Management: использование @Transactional против использования AOP (<aop: advisor)

У меня путаница по поводу управления транзакциями Spring. В моем приложении я реализовал управление транзакциями, используя @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 в классе обслуживания:

    <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 также является реализацией AOP весной. Может кто-нибудь объяснить мне, как?

1 ответ

Решение

Не будет

Выгоды

Если вам не нужны какие-то очень конкретные требования или у вас нет проблем с производительностью, вам не следует изобретать велосипед. Spring - почти идеально разработанный, протестированный и заостренный инструмент, который можно заменить даже для серверов корпоративных приложений. @Transactional это декларативный способ управления транзакциями, он гораздо удобнее и удобочитаемее, чем любые другие конфигурации XML. Его преимущества включают автоматическую обработку всех аспектов управления транзакциями декларативным способом: уровни изоляции и распространения (управлять вложенными транзакциями нелегко), тайм-ауты, условия отката и отдельные TransactionManager для каждого отдельного метода класса вашего сервиса. Легко читается, прост в настройке, прост в использовании.

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

Когда вы видите этот метод, легко понять его транзакционные атрибуты (без предоставления деталей реализации транзакций в методе). В случае простого AOP каждый раз, когда вы хотите узнать, что происходит в этом методе, вы должны проверить свою конфигурацию xml и найти соответствующий метод, который менее элегантен.

С другой стороны, очень трудно отлаживать или использовать эти прокси для любого другого декларативного управления. Например, это сложно (но не невозможно) извлечь ваш компонент из контекста и извлечь что-то из упакованного компонента, используя отражение (скажем, для целей мониторинга). Кроме того, когда bean-компонент вызывает один из его методов, он не будет делегирован прокси, потому что ваш bean-компонент ничего не знает о прокси, поэтому this относится к самому бобу. Единственный способ вылечить это - предоставить поле "self" и установить его в постпроцессоре пользовательского компонента (но ваша реализация тоже страдает от этого).

Реализация

Если Spring настроен на использование управления транзакциями, он ищет @Transactional аннотация на определения бина и создает автоматически сгенерированный прокси AOP, который является подклассом вашего бина. Поведение Spring прокси по умолчанию просто делегирует вызовы метода базовому компоненту. Затем Spring внедряет TransactionInterceptor с необходимыми TransactionManager. Код перехватчика выглядит довольно просто:

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, настраивает время ожидания и уровень изоляции, затем вызывает метод. После этого решается, должна ли транзакция быть зафиксирована или откатана (выбор делается на основе перехваченного исключения и времени).

Другие вопросы по тегам