Spring宣告式事務控制原理之宣告式事務的重要元件在AOP中的應用
重要元件有:
1.InfrastructureAdvisorAutoProxyCreator 後置處理器
2.BeanFactoryTransactionAttributeSourceAdvisor 事務通知器
3.TransactionAttributeSource 事務屬性解析器
4.TransactionInterceptor 事務攔截器,作為通知advice
1. InfrastructureAdvisorAutoProxyCreator的作用
InfrastructureAdvisorAutoProxyCreator實現了SmartInstantiationAwareBeanPostProcessor是一個後置處理器,在bean建立過程的最後一步會呼叫InfrastructureAdvisorAutoProxyCreator的postProcessAfterInitialization方法對bean進行代理增強
AbstractAutowireCapableBeanFactory.class
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 遍歷執行bean後置處理器的postProcessAfterInitialization方法
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
2. BeanFactoryTransactionAttributeSourceAdvisor的作用
這是一個Advisor(通知器),在AbstractAutoProxyCreator#wrapIfNecessary方法中獲取當前bean相關的全部切面,用於代理類的生成
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 當前bean無切面,所以無需生成代理物件
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 獲取當前bean相關的全部切面
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;
}
// 當前bean無切面
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
3.TransactionAttributeSource的作用
主要作用解析某方法中是否包含@Transactional,解析Transactional註解的各個屬性封裝成配置類備用;有兩個重要地方用到第一個地方用來判斷bean裡是否包含@Transactional,以決定是否為此bean進行事務代理增強;第二個地方用來判斷bean具體的方法上是否包含@Transactional,以決定是否對此方法進行事務攔截
第一個:在2中獲取當前bean相關的全部切面的AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean#findEligibleAdvisors#findAdvisorsThatCanApply裡用到
AbstractAdvisorAutoProxyCreator.class
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 獲取當前類相關的全部切面
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 獲取容器裡全部切面
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 過濾切入當前bean的切面
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 切面按指定順序排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 過濾於當前Bean無關的Advisor(通知器)
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
AopUtils.class
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 判斷當前bean是否在這個切面的覆蓋下
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
// 用到了advisor的切入點PointCut來判斷這個bean裡的那個方法符合切入點,也就是存在@Transactional註解,這裡切入點判斷某方法是否包含@Transactional註解時用到了TransactionAttributeSource
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
第二個地方:以JDK動態代理舉例在代理類呼叫方法時會進入JdkDynamicAopProxy的invoke方法,在此方法裡會獲取當前方法的攔截器鏈,然後組裝建立一個方法執行器,用來管理各個攔截方法按順序呼叫,如第一個地方一樣此處用到了TransactionAttributeSource來判斷此方法是否符合BeanFactoryTransactionAttributeSourceAdvisor的切入點即是否有@Transactional註解
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 獲取方法的攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 根據方攔截器鏈建立方法執行器
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 方法執行器啟動
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
4.TransactionInterceptor
這是一個方法攔截器也可以理解為是一個定義了事務處理的橫切邏輯的通知advice,主要用在代理物件執行帶有@Transactional的方法時呼叫invoke方法對原方法進行攔截增強,織入事務橫切邏輯(作為3中第二個地方攔截器鏈的一員)
TransactionInterceptor.class
public Object invoke(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, invocation::proceed);
}
進入invokeWithinTransaction方法
TransactionAspectSupport.class
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
// 獲取事務屬性解析器ProxyTransactionManagementConfiguration中注入
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 獲取事務管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal;
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;
}
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
相關文章
- Spring宣告式事務控制Spring
- Spring中的AOP,以及宣告式事務 @Transactional無法攔截事務Spring
- Spring的事務管理(二)宣告式事務管理Spring
- Spring-宣告式事務Spring
- 三 Spring 宣告式事務Spring
- Spring宣告式事務@Transactional使用Spring
- spring宣告式事務管理配置Spring
- Spring的四種宣告式事務的配置-Hibernate事務Spring
- Spring @Transactional 宣告式事務揭祕Spring
- 深刻理解Spring宣告式事務Spring
- Spring MVC + Mybatis + Spring Aop宣告式事務管理沒有作用SpringMVCMyBatis
- 全面分析 Spring 的程式設計式事務管理及宣告式事務管理Spring程式設計
- 五(二)、spring 宣告式事務xml配置SpringXML
- Spring筆記(4) - Spring的程式設計式事務和宣告式事務詳解Spring筆記程式設計
- Spring宣告式事務的兩種實現方式Spring
- Spring事務的介紹,以及基於註解@Transactional的宣告式事務Spring
- Spring宣告式事務純xml模式回顧SpringXML模式
- JavaEE(12)Spring整合Mybaits、宣告式事務JavaSpringAI
- Spring boot +mybatis 實現宣告式事務管理Spring BootMyBatis
- spring宣告式事務無法關閉sessionSpringSession
- Springboot資料庫事務處理——Spring宣告式事務Spring Boot資料庫
- SpringMVC、MyBatis 宣告式事務管理SpringMVCMyBatis
- 宣告式事務能否和程式設計式事務巢狀使用?程式設計巢狀
- 筆記53-Spring jdbcTemplate&宣告式事務筆記SpringJDBC
- Spring程式設計式和宣告式事務例項講解Spring程式設計
- Spring宣告式事務注意點,以及不生效情況Spring
- springboot專案-宣告式事務失效Spring Boot
- Spring宣告式事務管理出錯示例與解決之道Spring
- Spring/SpringBoot中的宣告式事務和程式設計式事務原始碼、區別、優缺點、適用場景、實戰Spring Boot程式設計原始碼
- JavaBean分散式應用的事務控制效率?JavaBean分散式
- 分散式事務之Spring事務與JMS事務(二)分散式Spring
- 保護億萬資料安全,Spring有“宣告式事務”絕招Spring
- spring事物配置,宣告式事務管理和基於@Transactional註解的使用Spring
- Spring中的事務控制Spring
- EAS_AOP分散式事務分散式
- 分散式事務(3)---RocketMQ實現分散式事務原理分散式MQ
- 事務使用中如何避免誤用分散式事務分散式
- 分散式事務(一)—分散式事務的概念分散式