spring源码分析之——spring 事务管理实现方式 (不太清晰,不明白aop会看不懂)

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

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

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

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

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

Java代码
2019102020044\_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代码
2019102020044\_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代码
2019102020044\_3.png

  1. new TxAdviceBeanDefinitionParser()

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

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

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

Java代码
2019102020044\_4.png

  1. public BeanDefinition parse(Element element, ParserContext parserContext) {
  2. return findParserForElement(element, parserContext).parse(element, parserContext);
  3. }

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

Java代码
2019102020044\_5.png

  1. TxAdviceBeanDefinitionParser

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

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

Java代码
2019102020044\_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代码
2019102020044\_7.png

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

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

Java代码
2019102020044\_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代码
2019102020044\_9.png

  1. Class beanClass = getBeanClass(element);

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

Java代码
2019102020044\_10.png

  1. @Override
  2. protected Class getBeanClass(Element element) {
  3. return TransactionInterceptor.class;
  4. }

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

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

Java代码
2019102020044\_11.png

  1. public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable

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

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

Java代码
2019102020044\_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() {
  36. public Object doInTransaction(TransactionStatus status) {
  37. TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
  38. try {
  39. return invocation.proceed();
  40. }
  41. catch (Throwable ex) {
  42. if (txAttr.rollbackOn(ex)) {
  43. // A RuntimeException: will lead to a rollback.
  44. if (ex instanceof RuntimeException) {
  45. throw (RuntimeException) ex;
  46. }
  47. else {
  48. throw new ThrowableHolderException(ex);
  49. }
  50. }
  51. else {
  52. // A normal return value: will lead to a commit.
  53. return new ThrowableHolder(ex);
  54. }
  55. }
  56. finally {
  57. cleanupTransactionInfo(txInfo);
  58. }
  59. }
  60. });
  61. // Check result: It might indicate a Throwable to rethrow.
  62. if (result instanceof ThrowableHolder) {
  63. throw ((ThrowableHolder) result).getThrowable();
  64. }
  65. else {
  66. return result;
  67. }
  68. }
  69. catch (ThrowableHolderException ex) {
  70. throw ex.getCause();
  71. }
  72. }
  73. }
  74. 哦,原来就是在这里控制了method invocation(spring aop是基于method的)!根据我们的配置,来决定

    是不是对method使用事务。

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

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

    赞(0) 打赏
    版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring源码分析之——spring 事务管理实现方式 (不太清晰,不明白aop会看不懂)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址

    © 2014 - 2019 Java 技术驿站   网站地图  | 

    icp 湘ICP备14000180

    >>> 网站已平稳运行:

    觉得文章有用就打赏一下文章作者

    支付宝扫一扫打赏

    微信扫一扫打赏