How Does Spring’s @Transactional Work? A Deep Dive into AOP and Transaction Management
This article explains the purpose and inner workings of Spring’s @Transactional annotation, detailing how AOP creates proxies, defines pointcuts, and orchestrates transaction management through BeanPostProcessors, advisors, interceptors, and the TransactionInterceptor, illustrated with source code snippets and diagrams.
@Transactional Annotation Overview
@Transactionalis Spring’s declarative transaction management annotation. It enables transaction start, commit, or rollback via AOP.
Using @Transactional lets Spring manage transactions automatically, reducing boilerplate and keeping business code clean.
Spring implements @Transactional based on AOP and dynamic proxies. The process involves defining a pointcut on methods annotated with @Transactional, creating proxy objects during bean initialization, and applying around advice.
Speculative Implementation of Declarative Transactions in Spring
When a method is marked with @Transactional, Spring defines a pointcut to identify it for proxying. During bean post‑processing, Spring generates a proxy and injects the transaction advice, similar to an @Around interceptor.
The proxy logic retrieves the transaction attribute source, determines the appropriate TransactionInterceptor, and invokes the target method within a transaction.
Role of @Transactional
The annotation defines the injection point for the proxy. Spring’s AnnotationAwareAspectJAutoProxyCreator (a BeanPostProcessor) creates the proxy in postProcessAfterInstantiation if the pointcut matches.
Spring registers a BeanFactoryTransactionAttributeSourceAdvisor which acts as the pointcut. If the advisor applies to a bean, a proxy is created and the advisor is attached.
AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method method, Class<?> targetClass)determines transaction attributes.
Finally, SpringTransactionAnnotationParser#parseTransactionAnnotation parses the annotation.
@Override
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
// Analyze if method is annotated with @Transactional
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
} else {
return null;
}
}The above code decides whether to create a proxy based on the presence of @Transactional.
Dynamic Proxy Logic Implementation
The AOP proxy ultimately invokes DynamicAdvisedInterceptor#intercept.
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// proxy creation logic...
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
} else {
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}The interceptor chain includes TransactionInterceptor, which implements the actual transaction logic.
TransactionInterceptor – The Final Transaction Manager
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}Inside invokeWithinTransaction, Spring obtains the TransactionAttribute, determines the PlatformTransactionManager, creates a transaction if necessary, proceeds with the method call, and commits or rolls back based on the outcome.
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
retVal = invocation.proceedWithInvocation();
} catch (Throwable ex) {
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
} finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
} else {
// CallbackPreferringPlatformTransactionManager handling omitted for brevity
}
}Summary
The article walks through the complete flow of how Spring uses AOP to implement @Transactional, from pointcut definition and proxy creation to the final transaction commit or rollback performed by TransactionInterceptor.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Interview Crash Guide
Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
