天天看點

spring源碼系列9:AOP源碼解析之事務代理的建立

回顧下AOP相關知識點:

  1. 靜态代理與JDK動态代理與CGLIB動态代理
  2. Spring中的InstantiationAwareBeanPostProcessor和BeanPostProcessor的差別
  3. spring源碼系列8:AOP源碼解析之代理的建立

我們總結出AOP公式

  • JDK動态代理(Proxy+InvocationHandler)+advised
  • CGLB動态代理(Enhancer+MethodInterceptor)+advised

本質都是在記憶體中生成了新的位元組碼類。

這節我們看看事務是如何利用AOP實作的。

事務代理生成過程

一、@EnableTransactionManagement配置事務環境

@EnableTransactionManagement的@Import(TransactionManagementConfigurationSelector.class)引入TransactionManagementConfigurationSelector.class。此類

@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {
						TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}           

PROXY:情況下,會注冊兩個類:

AutoProxyRegistrar:

實作了ImportBeanDefinitionRegistrar。其接口方法registerBeanDefinitions會向倉庫注冊Bean定義 InfrastructureAdvisorAutoProxyCreator。

InfrastructureAdvisorAutoProxyCreator

繼承了AbstractAdvisorAutoProxyCreator間接繼承了

AbstractAutoProxyCreator

在AOP代理生成那一節,我們講過。

AnnotationAwareAspectJAutoProxyCreator

也是間接繼承了

AbstractAutoProxyCreator

AbstractAutoProxyCreator

在AOP實作原理中做了大部分工作。

從這一點看,事務代理對象建立過程,與AOP代理對象過程是一樣的,關鍵就在這個AbstractAutoProxyCreator類

ProxyTransactionManagementConfiguration

是一個@Configuration。有三個@Bean注解方法。

  • transactionAdvisor()
  • transactionAttributeSource()
  • transactionInterceptor()
@Configurationpublic class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
		advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}}           

1.BeanFactoryTransactionAttributeSourceAdvisor:

首先:transactionAdvisor()方法會向倉庫中注冊一個BeanFactoryTransactionAttributeSourceAdvisor。

spring源碼系列9:AOP源碼解析之事務代理的建立

從其繼承關系上看,他是一個Advisor,并且還是PointcutAdvisor.關于Advisor,上節我們分析過他是封裝了(Advice+Pointcut)

既然都有了Advisor了,那Advice和Pointcut在哪裡呢?

BeanFactoryTransactionAttributeSourceAdvisor有一個pointcut 屬性,會new 一個TransactionAttributeSourcePointcut。

private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};           
spring源碼系列9:AOP源碼解析之事務代理的建立

從其繼承關系,我們可以看出他其實就是一個Pointcut。

至此,就剩下Advice沒有被發現。

2.TransactionAttributeSource:

其次:transactionAttributeSource()會向倉庫中注冊一個AnnotationTransactionAttributeSource。這個AnnotationTransactionAttributeSource幹嘛用的呢?

BeanFactoryTransactionAttributeSourceAdvisor.setTransactionAttributeSource(transactionAttributeSource())屬性值private TransactionAttributeSource transactionAttributeSource;private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};TransactionAttributeSourcePointcut的matche方法@Override
	public boolean matches(Method method, Class<?> targetClass) {
		if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
			return false;
		}
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}           

AnnotationTransactionAttributeSource對象會指派給BeanFactoryTransactionAttributeSourceAdvisor的

transactionAttributeSource

屬性。

pointcut

屬性初始化時,new 一個

TransactionAttributeSourcePointcut類

并實作

getTransactionAttributeSource()

方法,

getTransactionAttributeSource()

方法正好傳回了

transactionAttributeSource

也就是說TransactionAttributeSourcePointcut的getTransactionAttributeSource()方法傳回的是AnnotationTransactionAttributeSource

3.TransactionInterceptor :

最後:transactionInterceptor()方法,會向倉庫中注冊一個TransactionInterceptor類。

spring源碼系列9:AOP源碼解析之事務代理的建立

TransactionInterceptor從繼承關系看他是一個Advice. 也就是增強器,是對事務真正處理地方。

有了Advice+Pointcut。Advice+Pointcut = Advisor 。 Advisor+TargetSource = Advised

有了Advised ,這樣spring事務不正是套用了AOP的基礎嗎。

二、代理的生成

在AOP源碼分析那一節,我們講過,postProcessAfterInitialization後置初始化方法中,wrapIfNecessary 滿足條件,才建立代理。

@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;}           

而這個條件就是:getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 能夠擷取适用于目前bean的Advisor

1.Advisor尋找

我們回顧上節:

getAdvicesAndAdvisorsForBean 經過

AbstractAdvisorAutoProxyCreator.findEligibleAdvisors

的調用,

AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass)

的調用,最終會調用

AopUtils.canApply

來判斷某個Advisor是否适用于目前類。

我們來看看canApply方法

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;
		}
	}           

上文提到,

  • BeanFactoryTransactionAttributeSourceAdvisor 是一個PointcutAdvisor類型的Advisor
  • BeanFactoryTransactionAttributeSourceAdvisor中new 一個TransactionAttributeSourcePointcut。

是以此處會走:

canApply(pca.getPointcut(), targetClass, hasIntroductions)分支。

pca.getPointcut()

傳回的是

TransactionAttributeSourcePointcut

進一步分析重載方法canApply(Pointcut pc, Class

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}

		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
		classes.add(targetClass);
		for (Class<?> clazz : classes) {
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			for (Method method : methods) {
				if ((introductionAwareMethodMatcher != null &&
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}           
  • 先ClassFilter.matches 校驗一次。

    TransactionAttributeSourcePointcut

    的父類

    StaticMethodMatcherPointcut.classFilter= ClassFilter.TRUE

    表示類檢查全部通過
  • 再MethodMatcher.matches 方法進行校驗
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
			return false;
		}
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}}           

matches方法會調用

getTransactionAttributeSource()

擷取一個

TransactionAttributeSource

對象,通過

TransactionAttributeSource.getTransactionAttribute(method, targetClass)

,來判斷适應性。

關于

getTransactionAttributeSource()

上文講過。會傳回一個

AnnotationTransactionAttributeSource

執行個體對象。

也就是說:TransactionAttributeSourcePointcut 的 matches()方法是通過AnnotationTransactionAttributeSource.getTransactionAttribute(method, targetClass)來實作的。

來看看getTransactionAttribute()方法

@Override
	public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}

		// First, see if we have a cached value.
		Object cacheKey = getCacheKey(method, targetClass);
		TransactionAttribute cached = this.attributeCache.get(cacheKey);
		if (cached != null) {
			// Value will either be canonical value indicating there is no transaction attribute,
			// or an actual transaction attribute.
			if (cached == NULL_TRANSACTION_ATTRIBUTE) {
				return null;
			}
			else {
				return cached;
			}
		}
		else {
			// We need to work it out.
			TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
			// Put it in the cache.
			if (txAttr == null) {
				this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
			}
			else {
				String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
				if (txAttr instanceof DefaultTransactionAttribute) {
					((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
				}
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}           

這裡用了一個緩存,但重點在這個

TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);

protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
		// Don't allow no-public methods as required.
		
		// 非public方法事務不生效。
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// Ignore CGLIB subclasses - introspect the actual user class.
		Class<?> userClass = ClassUtils.getUserClass(targetClass);
		// The method may be on an interface, but we need attributes from the target class.
		// If the target class is null, the method will be unchanged.
		
		// 擷取真實的方法(有接口方法的,要擷取實作類上的那個方法)
		Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
		// If we are dealing with method with generic parameters, find the original method.
		specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

		// First try is the method in the target class.
		//首先檢視實作類方法上是否有@Transactional注解
		TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
		if (txAttr != null) {
			return txAttr;
		}

		// Second try is the transaction attribute on the target class.
		//其次檢視實作類方法所在類上是否有@Transactional注解
		txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
			return txAttr;
		}

		if (specificMethod != method) {
			// Fallback is to look at the original method.
			//還不行去看接口方法上是否有@Transactional注解
			txAttr = findTransactionAttribute(method);
			if (txAttr != null) {
				return txAttr;
			}
			// Last fallback is the class of the original method.
			//最後看接口上是否有@Transactional注解
			txAttr = findTransactionAttribute(method.getDeclaringClass());
			if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
				return txAttr;
			}
		}

		return null;
	}           

由此:我們們也終于知道,@Transactional注解的查找順序,實作類方法–》實作類–》接口方法–》接口

我們在這四個地方添加@Transactional注解都會使事務生效。

在這四個地方任一一個地方找到了@Transactional注解,說明

BeanFactoryTransactionAttributeSourceAdvisor

适用于目前類,getAdvicesAndAdvisorsForBean 的傳回不為空。接下來就可以建立動态代理了。

2.代理的生成

// 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;
		}           

createProxy()方法,在spring源碼系列8:AOP源碼解析之代理的建立一節我們一節分析過了。

最終的結果就是通過

CglibAopProxy. getProxy()傳回代理對象

或者

JdkDynamicAopProxy. getProxy()傳回代理對象

總結:

  1. AOP = 動态代理+ Advised(Adisor+TargetSource);
  2. Adisor = Advice+Pointcut

繼續閱讀