從上一篇文章中可以知道《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);
}
至此,已經找到自定義命名空間和標籤的解析器,該過程主要分爲以下幾步:
- 獲取所有META-INF/spring.handlers中的自定義標籤命名空間和命名空間處理器的映射關係
- 調用命名空間處理器的init()方法註冊標籤解析器
- 調用相對應的解析器的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。
但是,我們並沒有在這個解析中看到事務相關的實質性的內容,例如:
- @Transactional事務註解的解析
- 在什麼場景下需要進行事務的增強
- 如何進行事務的增強
從前面的分析中我們並找到通過某個方法的調用去實現事務功能,好像走進了一條死衚衕。當細心的讀者會發現,在註冊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/>的解析過程。總結下整個解析步驟:
- 通過命名空間獲取命名空間處理類,並在命名空間處理類中註冊解析器
- 通過解析器解析自定義標籤<tx:annotation-driven/>,解析目的主要是向容器中註冊四個bean
- 在BeanPostProcessor中判斷哪些bean需要被增強,如果需要,則創建bean的動態代理對象,並返回