- An overview of the
- Using the @ Transactional
- The principle of analysis
- BeanDefinition and BeanPostProcessor
- postProcessAfterInitialization
- invoke on proxy instance
- TransactionInterceptor
- TransactionInterceptor vs TransactionManager vs JdbcTemplate vs TransactionSynchronizationManager
- Links
An overview of the
Transactional @Transactional is an annotation used by Spring transaction management. When you use this annotation in a method, that method is Transactional. Operations within that method are either committed or rolled back together. There are a lot of knowledge points about the working principle behind it. The focus of this paper is to sort out the whole process. The more specific transaction configuration attributes and the integration of Spring transactions with third-party ORM frameworks are not the focus of this paper.
Using the @ Transactional
Enable support for the @Transactional annotation in the application-context.xml configuration file, configure the Scan path, and so on
<tx:annotation-driven />
Copy the code
Annotate the Service method
@Service public class UserServiceImpl implements UserService { @Transactional public int register(User user) { addUser(user); auditLog(user); }}Copy the code
That’s the simple configuration and use of @Transactional to make it work;
The principle of analysis
@Transactional does something like this,
try {
tx.begin();
businessLogic();
tx.commit();
} catch(Exception ex) {
tx.rollback();
throw ex;
}
Copy the code
This is also what the TransactionManager TransactionManager normally does, except that a single annotation here “completes” the way the transaction management code is written by hand; All other Service methods that need to start a transaction simply configure this annotation without having to write code. This is the idea of faceted programming, and Spring AOP does this with annotations; With the XML configuration and code above, take a closer look at how Spring finally implements this aspect.
BeanDefinition and BeanPostProcessor
The first is to tx namespace support, registered in the TxNamespaceHandler AnnotationDrivenBeanDefinitionParser parser, provide support for annotations – driven attribute analysis; I’m going to construct three important Beandefinitions and one BeanPostProcessor, BeanDefinition,
- TransactionAttributeSource / / used to get the @ Transactional annotation properties
-
TransactionInterceptor // The method interceptor relies on the TransactionManager Bean; Rely on transactionAttributeSource
- TransactionAttributeSourceAdvisor transactionAttributeSource rely on / /; Rely on TransactionInterceptor; TransactionAttributeSourceAdvisor PointcutAdvisor, Spring AOP’s content, including pointcuts and advice BeanPostProcessor,
- InfrastructureAdvisorAutoProxyCreator / / used to create the Proxy
postProcessAfterInitialization
Of course a Bean rely on UserService beans, must first initialize UserServiceImpl, rear application processor, when using rear InfrastructureAdvisorAutoProxyCreator processor, It turns out that UserServiceImpl uses the @Transaction annotation, so it should be proxied. That is, create a proxy here and return the proxy instance to the Bean that depends on UserService. Analyze the process of creating a proxy,
// Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors ! = DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; }Copy the code
Get the TransactionInterceptor method interceptor before creating the proxy, and pass it to createProxy. The process in createProxy is the same as the Spring AOP process. The method interceptor is organized into an Advisor and creates an InvocationHandler based on whether the proxy interface is created. In this case, the InvocationHandler is JdkDynamicAopProxy. It ultimately creates the proxy instance,
@Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } Class<? >[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }Copy the code
invoke on proxy instance
When the Service method is called, the proxy class method is actually called. The proxy instance created by JdkDynamicAopProxy as InvocationHandler is called, which is eventually called to the INVOKE method of JdkDynamicAopProxy. JDK dynamic proxy), and the invoke method will use the previous TransactionInterceptor,
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
Copy the code
Will eventually call ReflectiveMethodInvocation TransactionInterceptor invoke method
TransactionInterceptor
The Invoke of the TransactionInterceptor finds traces of transaction management by calling its parent class invokeWithinTransaction to do something like this,
if (txAttr == null || ! (tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } commitTransactionAfterReturning(txInfo); return retVal; }Copy the code
Tm is the TransactionManager, which is relied on by the TransactionInterceptor in the BeanDefinition registration phase. The analysis doesn’t show up here
tx.begin()
tx.commit()
tx.rollback()
Copy the code
And so on, actually these affairs related method, all are done by TransactionManager, tracking createTransactionIfNecessary method above, The getTransaction method in TransactionManager performs the doBegin operation. The doBegin method creates a database Connection from the TransactionManager dataSource. The dataSource is bound to a ThreadLocal thread.
TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder());
Copy the code
CommitTransactionAfterReturning equivalent of MIT, tx.com completeTransactionAfterThrowing is equivalent to the tx. Rollback;
TransactionInterceptor vs TransactionManager vs JdbcTemplate vs TransactionSynchronizationManager
Spring uses BeanPostProcessor to delegate classes that use the @Transactional annotation. The InvocationHandler created by BeanPostProcessor uses the TransactionInterceptor method interceptor, where it implements transaction-managed operations. Transaction management is handled by the TransactionInterceptor’s TransactionManager, which uses the dataSource to create database links.
However, there is still a problem. The Connection created by the TransactionInterceptor is used by businessLogic and UserServiceImpl# Register. Here we take JdbcTemplate as an example to analyze, JdbcTemplate operation needs to obtain the database Connection, it is implemented like this,
Connection con = DataSourceUtils.getConnection(this.obtainDataSource());
Copy the code
Trace the DataSourceUtils code and you’ll eventually find something like this
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);
Copy the code
So is that of the bound above, bound to the ThreadLocal, are obtained from ThreadLocal TransactionSynchronizationManager related; In fact, Mybatis uses Spring transaction management, its way of obtaining links is also using DataSourceUtils;
Links
- How Does Spring @Transactional Really Work?