- 事務(wù)方法通過cglib生成
- 執(zhí)行方法的時候,
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
chain里有4個interceptor,分別是
- ExposeInvocationInterceptor:用于設(shè)置和恢復(fù)原來的MethodInvocation。
- MethodBeforeAdviceInterceptor:一般用于設(shè)置數(shù)據(jù)源(order在transactionManager前面)
- AfterReturningAdviceInterceptor:一般用于clear數(shù)據(jù)源
- TransactionInterceptor:執(zhí)行事務(wù)
3是在4之后執(zhí)行的,看代碼
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
mi.proceed()是執(zhí)行后面的代碼,是個鏈?zhǔn)綀?zhí)行方式,和filter原理一樣。
@Override
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
當(dāng)整個鏈執(zhí)行完后,進(jìn)入invokeJoinpoint(),這里執(zhí)行你的業(yè)務(wù)方法。
你的業(yè)務(wù)方法a.method()里如果調(diào)用了另一個帶事務(wù)的方法b.method(),那么b.method()同樣是按上面的執(zhí)行順序。但是b.method獲取TransactionStatus的時候會發(fā)現(xiàn)當(dāng)前線程中有了SessionHolder,因此會被認(rèn)為不是一個new transaction。而a.method會被認(rèn)為是new transaction。
在TransactionInterceptor執(zhí)行中,最后
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
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;
}
...
}
commitTransactionAfterReturning()中會判斷如果transactionStatus不是new的,不執(zhí)行doCommit(),因此b.method()執(zhí)行后不會commit,a.method執(zhí)行后會commit。
以上是對非跨庫事務(wù)分析,如果跨庫了就變成XA,需要引入2PC等。
如果a.method1()調(diào)用了a.method2(),那么a.method2()是不經(jīng)過cglib生成的,是直接調(diào)用,不走事務(wù)的4個interceptor。
a.method()調(diào)用b.method()才會走4個Interceptor。
a.method()調(diào)用b.method(),b.method()調(diào)用c.method(),如果他們配置了不同的datasource,只有a上配置的datasource起作用,b和c的不起作用,因為在b,c會判斷當(dāng)前threadlocal中已經(jīng)有sesessionHolder了,會被認(rèn)為是一個事務(wù)中的。
結(jié)論:讀寫事務(wù)要區(qū)分,嚴(yán)禁在讀服務(wù)中調(diào)用寫服務(wù)。
下圖:
類內(nèi)調(diào)用,只有入口方法上的事務(wù)才起作用,被調(diào)用的方法上的事務(wù)配置是不會有影響的。
類外調(diào)用,那么調(diào)用方法和被調(diào)用方法都會被aop代理。
When you call a method without @Transactional
within a transaction block, the parent transaction will continue to the new method. It will use the same connection from the parent method(with @Transactional
) and any exception caused in the called method(without @Transactional
will cause the transaction to rollback as configured in the transaction definition.
If you call a method with a @Transactional
annotation from a method with @Transactional
within the same instance, then the called methods transactional behavior will not have any impact on the transaction. But if you call a method with a transaction definition from another method with a transaction definition, and they are in different instances, then the code in the called method will follow the transaction definitions given in the called method.
You can find more details in the section Declarative transaction management of spring transaction documentation.
Spring declarative transaction model uses AOP proxy. so the AOP proxy is responsible for creation of the transactions. The AOP proxy will be active only if the methods with in the instance are called from out side the instance.
疑問:cglib會對每個方法都進(jìn)行“代理”的,為什么類內(nèi)方法調(diào)用不經(jīng)過那些Interceptor呢?
在類內(nèi)調(diào)用時,調(diào)用called method的對象是FastClassBySpringCGLIB,并不是EnhancerBySpringCGLIB,F(xiàn)astClass并沒有對類增強,僅僅是加快反射調(diào)用速度,具體分析見https://dzone.com/articles/cglib-missing-manual。