spring源码分析之——spring 事务管理实现方式

 2019-10-17 21:30  阅读(776)
文章分类:Spring boot

注意:这里只是分析spring事务的实现方式。也就是spring的事务管理是怎么发生作用的,而不分析具体的实现细节(细节将在下一篇里面分析).

转载:http://michael-softtech.iteye.com/blog/813835

紧接着上一篇提到的,Spring是通过NameSpaceHandler来解析配置文件中的标签的。下面就已事务的配置为例,讲述一下

事务配置的标签的解析过程,从来理解事物是如何通过aop产生作用的。

Java代码
2019101710061\_1.png

  1. <!– 以AspectJ方式 定义 AOP –>

  2. <aop:advisor pointcut=“execution(* commo.base.BaseManager.*(..))” advice-ref=“txAdvice”/>

  3. <aop:advisor pointcut=“execution(* com.*..*.service.*Manager.*(..))” advice-ref=“txAdvice”/>

  4. </aop:config>

  5. <!– 基本事务定义,使用transactionManager作事务管理,默认get* find*方法的事务为readonly,其余方法按默认设置.

  6. 默认的设置请参考Spring文档事务一章. –>

  7. </tx:attributes>

  8. </tx:advice>

    以上的配置相信很多人已经很熟悉了,在此不赘述。而是具体分析一下原理。

    先来分析…</tx:advice>。

tx是TransactionNameSpace。对应的是handler是TxNamespaceHandler.

这个类一个init方法:

Java代码
2019101710061\_2.png

  1. public void init() {
  2. registerBeanDefinitionParser(“advice”, new TxAdviceBeanDefinitionParser());
  3. registerBeanDefinitionParser(“annotation-driven”, new AnnotationDrivenBeanDefinitionParser());
  4. registerBeanDefinitionParser(“jta-transaction-manager”, new JtaTransactionManagerBeanDefinitionParser());
  5. }

这个方法是在DefaultNamespaceHandlerResolver的resolve中调用的。在为对应的标签寻找namespacehandler的时候,调用这个resolve方法。resolve方法先寻找namespaceUri对应的namespacehandler,如果找到了就先调用Init方法。

OK.我们的对应的解析器也注册了,那就是上面代码里面的

Java代码
2019101710061\_3.png

  1. new TxAdviceBeanDefinitionParser()

    那么,这个解析器是什么时候调用的哪?

    上一篇提到了,对应标签解析时会先选择namespacehandler,然后调用其parse方法。

    TxNamespaceHandler的parse方法在其父类NamespaceHandlerSupport中,代码如下:

Java代码
2019101710061\_4.png

  1. public BeanDefinition parse(Element element, ParserContext parserContext) {

  2. return findParserForElement(element, parserContext).parse(element, parserContext);

  3. }

    这下明白了吧?在解析出来的Document里面是一个Element,而这个Element的parse就是上面注册了的

Java代码
2019101710061\_5.png

  1. TxAdviceBeanDefinitionParser

    现在这个parser的parse方法在NamespaceHandlerSupport的parse方法中被调用了,下面我们来看看这个

    TxAdviceBeanDefinitionParser的parse方法吧,这个方法在TxAdviceBeanDefinitionParser的祖父类AbstractBeanDefinitionParser中:

Java代码
2019101710061\_6.png

  1. public final BeanDefinition parse(Element element, ParserContext parserContext) {

  2. AbstractBeanDefinition definition = parseInternal(element, parserContext);

  3. if (definition != null && !parserContext.isNested()) {

  4. try {

  5. String id = resolveId(element, definition, parserContext);

  6. if (!StringUtils.hasText(id)) {

  7. parserContext.getReaderContext().error(

  8. “Id is required for element ‘” + parserContext.getDelegate().getLocalName(element)

  9. + “‘ when used as a top-level tag”, element);

  10. }

  11. String[] aliases = new String[0];

  12. String name = element.getAttribute(NAME_ATTRIBUTE);

  13. if (StringUtils.hasLength(name)) {

  14. aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));

  15. }

  16. BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);

  17. registerBeanDefinition(holder, parserContext.getRegistry());

  18. if (shouldFireEvents()) {

  19. BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);

  20. postProcessComponentDefinition(componentDefinition);

  21. parserContext.registerComponent(componentDefinition);

  22. }

  23. }

  24. catch (BeanDefinitionStoreException ex) {

  25. parserContext.getReaderContext().error(ex.getMessage(), element);

  26. return null;

  27. }

  28. }

  29. return definition;

  30. }

    注意其中这样一行:

Java代码
2019101710061\_7.png

  1. AbstractBeanDefinition definition = parseInternal(element, parserContext);

    这个parseInternal是在TxAdviceBeanDefinitionParser的父类AbstractSingleBeanDefinitionParser中实现的,代码如下:

Java代码
2019101710061\_8.png

  1. @Override

  2. protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {

  3. BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();

  4. String parentName = getParentName(element);

  5. if (parentName != null) {

  6. builder.getRawBeanDefinition().setParentName(parentName);

  7. }

  8. Class beanClass = getBeanClass(element);

  9. if (beanClass != null) {

  10. builder.getRawBeanDefinition().setBeanClass(beanClass);

  11. }

  12. else {

  13. String beanClassName = getBeanClassName(element);

  14. if (beanClassName != null) {

  15. builder.getRawBeanDefinition().setBeanClassName(beanClassName);

  16. }

  17. }

  18. builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));

  19. if (parserContext.isNested()) {

  20. // Inner bean definition must receive same scope as containing bean.

  21. builder.setScope(parserContext.getContainingBeanDefinition().getScope());

  22. }

  23. if (parserContext.isDefaultLazyInit()) {

  24. // Default-lazy-init applies to custom bean definitions as well.

  25. builder.setLazyInit(true);

  26. }

  27. doParse(element, parserContext, builder);

  28. return builder.getBeanDefinition();

  29. }

    其中有一行:

Java代码
2019101710061\_9.png

  1. Class beanClass = getBeanClass(element);

    getBeanClass是在TxAdviceBeanDefinitionParser中实现的,很简单:

Java代码
2019101710061\_10.png

  1. @Override

  2. protected Class getBeanClass(Element element) {

  3. return TransactionInterceptor.class;

  4. }

    至此,这个标签解析的流程已经基本清晰了。那就是:解析除了一个以TransactionInerceptor为classname的beandefinition并且注册这个bean。剩下来要看的,就是这个TranscationInterceptor到底是什么?

    看看这个类的接口定义,就明白了:

Java代码
2019101710061\_11.png

  1. public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable

    这根本就是一个spring AOP的advice嘛!现在明白为什么事务的配置能通过aop产生作用了吧?

    下面具体看看这个advice的advice:

Java代码
2019101710061\_12.png

  1. public Object invoke(final MethodInvocation invocation) throws Throwable {

  2. // Work out the target class: may be null.

  3. // The TransactionAttributeSource should be passed the target class

  4. // as well as the method, which may be from an interface.

  5. Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);

  6. // If the transaction attribute is null, the method is non-transactional.

  7. final TransactionAttribute txAttr =

  8. getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);

  9. final PlatformTransactionManager tm = determineTransactionManager(txAttr);

  10. final String joinpointIdentification = methodIdentification(invocation.getMethod());

  11. if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {

  12. // Standard transaction demarcation with getTransaction and commit/rollback calls.

  13. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

  14. Object retVal = null;

  15. try {

  16. // This is an around advice: Invoke the next interceptor in the chain.

  17. // This will normally result in a target object being invoked.

  18. retVal = invocation.proceed();

  19. }

  20. catch (Throwable ex) {

  21. // target invocation exception

  22. completeTransactionAfterThrowing(txInfo, ex);

  23. throw ex;

  24. }

  25. finally {

  26. cleanupTransactionInfo(txInfo);

  27. }

  28. commitTransactionAfterReturning(txInfo);

  29. return retVal;

  30. }

  31. else {

  32. // It’s a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.

  33. try {

  34. Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,

  35. new TransactionCallback() {

    public Object doInTransaction(TransactionStatus status) {

    TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

    try {

    return invocation.proceed();

    }

    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.

    return new ThrowableHolder(ex);

    }

    }

    finally {

    cleanupTransactionInfo(txInfo);

    }

    }

    });

    // Check result: It might indicate a Throwable to rethrow.

    if (result instanceof ThrowableHolder) {

    throw ((ThrowableHolder) result).getThrowable();

    }

    else {

    return result;

    }

    }

    catch (ThrowableHolderException ex) {

    throw ex.getCause();

    }

    }

    }

    哦,原来就是在这里控制了method invocation(spring aop是基于method的)!根据我们的配置,来决定

    是不是对method使用事务。

    至此,spring的事务管理已经基本清晰了。就是解析出一个advice bean(of class : TransactionInterceptor)来,

    然后在aop中配置pointcut和这个advice,就能产生作用了!


    来源:[]()

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> spring源码分析之——spring 事务管理实现方式

相关推荐