2. 命名空間及自定義標籤的解析

從上一篇文章中可以知道《Spring事務實現概覽》中可以知道<tx:annotation-driven>爲整個事務實現的入口。通過對該標籤的解析來實現事務的管理。
本文以<tx:annotation-driven>爲入口,分析tx自定義標籤。

1. 自定義標籤解析入口

spring bean容器在解析配置文件的時候,除了正常解析<bean>外,還提供了自定義命名空間的解析入口(真的強大👍),那麼我們就以XmlBeanFactory爲入口,找到自定義標籤解析入口
XmlBeanFactory.java

	/**
	 *通過給定的資源創建XmlBeanFactory容器,資源就是配置文件,即上一篇文章中的context.xml
	 */
	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);//加載beanDefinition
	}

XmlBeanDefinitionReader.java中解析xml文件:

	/**
	 *實際從xml中加載bean definition的入口
	 */
	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			Document doc = doLoadDocument(inputSource, resource);//將resource轉化爲Document
			int count = registerBeanDefinitions(doc, resource);//註冊beanDefinition
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch (... ex) {//省略catch代碼
			throw ex;
		}
	}

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();//DefaultBeanDefinitionDocumentReader
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));//註冊
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

DefaultBeanDefinitionDocumentReader.java

	/**
	 *解析<beans/>下的標籤
	 */
	@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}


	@SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
	protected void doRegisterBeanDefinitions(Element root) {
		...
		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);//解析beanDefinition
		postProcessXml(root);
		...
	}
	/**
	 * Parse the elements at the root level in the document:
	 * "import", "alias", "bean".
	 * @param root the DOM root element of the document
	 */
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);//解析默認元素,即<bean/>
					}
					else {
						delegate.parseCustomElement(ele);//解析自定義元素,這就是解析<tx:annotation-driven/>的入口
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

	@Nullable
	public BeanDefinition parseCustomElement(Element ele) {
		return parseCustomElement(ele, null);
	}

	@Nullable
	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		//解析META-INF/spring.handlers,獲取NamespaceHandler,並調用init()方法進行註冊每一個標籤的解析器
		//tx命名空間使用的是TxNamespaceHandler
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);//DefaultNamespaceHandlerResolver.resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));//自定義標籤的解析,TxNamespaceHandler
	}

已經找到自定義標籤的解析入口,並獲取到TxNamespaceHandler對象,通過調用TxNamespaceHandler的parse方法對<tx:>命名空間中的不同標籤進行解析。

2. 確定<tx:annotation-driven>標籤解析器

TxNamespaceHandler.java

public class TxNamespaceHandler extends NamespaceHandlerSupport {
	static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
	static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
	//如果<annotation-driven/>標籤沒配置transaction-manager屬性,那麼默認爲transactionManager
	static String getTransactionManagerName(Element element) {
		return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
				element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
	}
	//初始化,註冊不同tx命名空間內不同標籤的解析器
	@Override
	public void init() {
		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());//annotation-driven標籤解析器
		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
	}
}

NamespaceHandlerSupport.java

	@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		//TxNamespaceHandler中註冊的parser,此處分析AnnotationDrivenBeanDefinitionParser(init中註冊的)
		BeanDefinitionParser parser = findParserForElement(element, parserContext);
		return (parser != null ? parser.parse(element, parserContext) : null);
	}

至此,已經找到自定義命名空間和標籤的解析器,該過程主要分爲以下幾步:

  1. 獲取所有META-INF/spring.handlers中的自定義標籤命名空間和命名空間處理器的映射關係
  2. 調用命名空間處理器的init()方法註冊標籤解析器
  3. 調用相對應的解析器的parse方法解析自定義標籤(AnnotationDrivenBeanDefinitionParser.parse)

接下來就是對自定義標籤<tx:annotation-driven/>的具體解析過程。

2. 解析事務自定義標籤<tx:annotation-driven/>


package org.springframework.transaction.config;

class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {

	/**
	 * 解析<tx:annotation-driven/>標籤,並註冊一個AutoProxyCreator
	 */
	@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		//註冊事務事件監聽器工廠,用於事務綁定事件
		registerTransactionalEventListenerFactory(parserContext);
		String mode = element.getAttribute("mode");
		//aspectj代理模式
		if ("aspectj".equals(mode)) {
			// mode="aspectj"
			registerTransactionAspect(element, parserContext);
			if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
				registerJtaTransactionAspect(element, parserContext);
			}
		}
		else {
			// mode="proxy",基於動態代理的
			AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
		}
		return null;
	}
	//設置屬性值
	private static void registerTransactionManager(Element element, BeanDefinition def) {
		def.getPropertyValues().add("transactionManagerBeanName",
				TxNamespaceHandler.getTransactionManagerName(element));
	}

	private static class AopAutoProxyConfigurer {
		/**
		 * 主要功能是在容器中註冊四個beanDefinition
		 * 1. InfrastructureAdvisorAutoProxyCreator:實現BeanPostProcessor增強bean
		 * 2. TransactionAttributeSourceAdvisor:封裝TransactionInterceptor和pointcut
		 * 3. AnnotationTransactionAttributeSource:通過getTransactionAttribute(Method method, @Nullable Class<?> targetClass);方法來獲取@Transactional註解中的事務屬性
		 * 4. TransactionInterceptor:事務攔截器處理類,對事務做增強處理
		 */
		public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
			//註冊InfrastructureAdvisorAutoProxyCreator的BeanDefinition
			AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
			
			String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
			if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
				Object eleSource = parserContext.extractSource(element);

				// 創建TransactionAttributeSource definition.
				RootBeanDefinition sourceDef = new RootBeanDefinition(
						"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
				sourceDef.setSource(eleSource);
				sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);//註冊AnnotationTransactionAttributeSource的BeanDefinition

				// 創建TransactionInterceptor definition.
				RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
				interceptorDef.setSource(eleSource);
				interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				registerTransactionManager(element, interceptorDef);//添加transactionManagerBeanName屬性
				interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));//添加sourceName屬性
				String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);//註冊TransactionInterceptor的BeanDefinition

				// 創建TransactionAttributeSourceAdvisor definition.
				RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
				advisorDef.setSource(eleSource);
				advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));//添加sourceName屬性
				advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);//添加interceptorName屬性
				if (element.hasAttribute("order")) {
					advisorDef.getPropertyValues().add("order", element.getAttribute("order"));//Advisor優先級
				}
				parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);//註冊advisor的BeanDefinition

				CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
				compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
				compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
				compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
				parserContext.registerComponent(compositeDef);
			}
		}
	}

}


至此,對於<tx:annotation-driven/>標籤的解析以及完成了。其目的就是在容器中註冊4個BeanDefinition。
但是,我們並沒有在這個解析中看到事務相關的實質性的內容,例如:

  1. @Transactional事務註解的解析
  2. 在什麼場景下需要進行事務的增強
  3. 如何進行事務的增強

從前面的分析中我們並找到通過某個方法的調用去實現事務功能,好像走進了一條死衚衕。當細心的讀者會發現,在註冊BeanDefinition的時候有一個InfrastructureAdvisorAutoProxyCreator類型的BeanDefinition,同時InfrastructureAdvisorAutoProxyCreator實現了BeanPostProcessor接口。
關於BeanPostProcessor請參考另一篇文章xxxx

通過BeanPostProcessor的特性,我們可以知道,在容器中的BeanDefinition實例化前後悔調用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法。InfrastructureAdvisorAutoProxyCreator的間接父類AbstractAutoProxyCreator中實現了這兩個方法

AbstractAutoProxyCreator.java

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}
	//創建代理類	
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
	
	/**
	 * 如果需要的話,對闖入的對象做合適的代理
	 * @param 原有bean
	 * @param 原有bean的名稱
	 * @param cacheKey the cache key for metadata access
	 * @return a proxy wrapping the bean, or the raw bean instance as-is
	 */
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return 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;
		}

		// 獲取Advisor, 如果有的話創建代理
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			//創建bean實例的代理
			//JDK動態代理的InvocationHandler爲JdkDynamicAopProxy
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

AbstractAdvisorAutoProxyCreator.java


	@Override
	@Nullable
	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
		//獲取合適的Advisor
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}
	/**
	 * Find all eligible Advisors for auto-proxying this class.
	 * @param beanClass the clazz to find advisors for
	 * @param beanName the name of the currently proxied bean
	 * @return the empty List, not {@code null},
	 * if there are no pointcuts or interceptors
	 * @see #findCandidateAdvisors
	 * @see #sortAdvisors
	 * @see #extendAdvisors
	 */
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		//獲取候選Advisors,即Advisor類型的所有bean,這裏實際獲取到的Advisor爲BeanFactoryTransactionAttributeSourceAdvisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		//需要應用於bean實例類的Advisor列表
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		//將Advisor列表按優先級排序
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}
	
	/**
	 * 判斷候選的Advisor是否應該被應用
	 * 
	 */
	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}

AopUtils.java


	/**
	 * 從候選的Advisor中查找需要應用於clazz類的Advisor列表
	 * 這裏的候選Advisor只有BeanFactoryTransactionAttributeSourceAdvisor,它實現了PointCutAdvisor接口
	 */
	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new LinkedList<>();
		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;
			}
			//判斷是否需要應用Advisor
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}


	/**
	 * 是否需要應用Advisor
	 */
	public static boolean canApply(Advisor advisor, Class<?> targetClass) {
		return canApply(advisor, targetClass, false);
	}
	
	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;
		}
	}
	
	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();//pc爲TransactionAttributeSourcePointcut類型
		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<>();
		if (!Proxy.isProxyClass(targetClass)) {
			classes.add(ClassUtils.getUserClass(targetClass));
		}
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
		//遍歷所有接口
		for (Class<?> clazz : classes) {
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			for (Method method : methods) {//遍歷接口中的所有方法
				if ((introductionAwareMethodMatcher != null &&
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
						//匹配是否需要代理,methodMatcher爲TransactionAttributeSourcePointcut類型
						//只要有一個方法匹配成功,那麼這個bean就需要被增強
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}

TransactionAttributeSourcePointcut.java

	/**
	 * 解析得到的@Transactional屬性信息不爲空,則匹配成功
	 */
	@Override
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
		if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
			return false;
		}
			TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

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

		// First, see if we have a cached value.
		//對已解析的數據做緩存,如果緩存中有則直接返回
		Object cacheKey = getCacheKey(method, targetClass);
		Object 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 (TransactionAttribute) cached;
			}
		}
		else {
			// We need to work it out.
			//獲取@Transactional註解中的屬性,
			//1. 方法註解優先於類註解
			//2. 實現類註解優先於接口註解
			TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
			//將屬性信息放入緩存中,如果沒有則緩存value爲空的DefaultTransactionAttribute對象
			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;
		}
	}

通過BeanPostProcessor,會對每個一個bean進行判斷是否需要動態代理增強,判斷條件爲接口方法和類是否存在@Transactional註解,如果存在該註解,則需要對這個bean進行增強,如果不存在則不需要增強。

動態代理類的InvocationHandler爲JdkDynamicAopProxy。即在JdkDynamicAopProxy中完成了事務的創建,提交,掛起,回滾等操作。

是的,到目前爲止,我們已經完成了自定義標籤<tx:annotation-driven/>的解析過程。總結下整個解析步驟:

  1. 通過命名空間獲取命名空間處理類,並在命名空間處理類中註冊解析器
  2. 通過解析器解析自定義標籤<tx:annotation-driven/>,解析目的主要是向容器中註冊四個bean
  3. 在BeanPostProcessor中判斷哪些bean需要被增強,如果需要,則創建bean的動態代理對象,並返回
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章