注意:這里只是分析spring事務(wù)的實現(xiàn)方式。也就是spring的事務(wù)管理是怎么發(fā)生作用的,而不分析具體的實現(xiàn)細節(jié)(細節(jié)將在下一篇里面分析).
轉(zhuǎn)載:http://michael-softtech.iteye.com/blog/813835
緊接著上一篇提到的,Spring是通過NameSpaceHandler來解析配置文件中的標簽的。下面就已事務(wù)的配置為例,講述一下
事務(wù)配置的標簽的解析過程,從來理解事物是如何通過aop產(chǎn)生作用的。
- <!-- 以AspectJ方式 定義 AOP -->
- <aop:config proxy-target-class="true">
- <aop:advisor pointcut="execution(* commo.base.BaseManager.*(..))" advice-ref="txAdvice"/>
- <aop:advisor pointcut="execution(* com.*..*.service.*Manager.*(..))" advice-ref="txAdvice"/>
- </aop:config>
-
- <!-- 基本事務(wù)定義,使用transactionManager作事務(wù)管理,默認get* find*方法的事務(wù)為readonly,其余方法按默認設(shè)置.
- 默認的設(shè)置請參考Spring文檔事務(wù)一章. -->
- <tx:advice id="txAdvice" transaction-manager="transactionManager">
- <tx:attributes>
- <tx:method name="find*" read-only="true"/>
- <tx:method name="get*" read-only="true"/>
- <tx:method name="query*" read-only="true"/>
- <tx:method name="*" read-only="false"/>
- </tx:attributes>
- </tx:advice>
以上的配置相信很多人已經(jīng)很熟悉了,在此不贅述。而是具體分析一下原理。
先來分析<tx:advice>...</tx:advice>。
tx是TransactionNameSpace。對應(yīng)的是handler是TxNamespaceHandler.
這個類一個init方法:
- public void init() {
- registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
- registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
- registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
- }
這個方法是在DefaultNamespaceHandlerResolver的resolve中調(diào)用的。在為對應(yīng)的標簽尋找namespacehandler的時候,調(diào)用這個resolve方法。resolve方法先尋找namespaceUri對應(yīng)的namespacehandler,如果找到了就先調(diào)用Init方法。
OK.我們的<tx:advice>對應(yīng)的解析器也注冊了,那就是上面代碼里面的
- new TxAdviceBeanDefinitionParser()
那么,這個解析器是什么時候調(diào)用的哪?
上一篇提到了,對應(yīng)標簽解析時會先選擇namespacehandler,然后調(diào)用其parse方法。
TxNamespaceHandler的parse方法在其父類NamespaceHandlerSupport中,代碼如下:
- public BeanDefinition parse(Element element, ParserContext parserContext) {
- return findParserForElement(element, parserContext).parse(element, parserContext);
- }
這下明白了吧?<tx:advice>在解析出來的Document里面是一個Element,而這個Element的parse就是上面注冊了的
- TxAdviceBeanDefinitionParser
現(xiàn)在這個parser的parse方法在NamespaceHandlerSupport的parse方法中被調(diào)用了,下面我們來看看這個
TxAdviceBeanDefinitionParser的parse方法吧,這個方法在TxAdviceBeanDefinitionParser的祖父類AbstractBeanDefinitionParser中:
- public final BeanDefinition parse(Element element, ParserContext parserContext) {
- AbstractBeanDefinition definition = parseInternal(element, parserContext);
- if (definition != null && !parserContext.isNested()) {
- try {
- String id = resolveId(element, definition, parserContext);
- if (!StringUtils.hasText(id)) {
- parserContext.getReaderContext().error(
- "Id is required for element '" + parserContext.getDelegate().getLocalName(element)
- + "' when used as a top-level tag", element);
- }
- String[] aliases = new String[0];
- String name = element.getAttribute(NAME_ATTRIBUTE);
- if (StringUtils.hasLength(name)) {
- aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
- }
- BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
- registerBeanDefinition(holder, parserContext.getRegistry());
- if (shouldFireEvents()) {
- BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
- postProcessComponentDefinition(componentDefinition);
- parserContext.registerComponent(componentDefinition);
- }
- }
- catch (BeanDefinitionStoreException ex) {
- parserContext.getReaderContext().error(ex.getMessage(), element);
- return null;
- }
- }
- return definition;
- }
注意其中這樣一行:
- AbstractBeanDefinition definition = parseInternal(element, parserContext);
這個parseInternal是在TxAdviceBeanDefinitionParser的父類AbstractSingleBeanDefinitionParser中實現(xiàn)的,代碼如下:
- @Override
- protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
- String parentName = getParentName(element);
- if (parentName != null) {
- builder.getRawBeanDefinition().setParentName(parentName);
- }
- Class beanClass = getBeanClass(element);
- if (beanClass != null) {
- builder.getRawBeanDefinition().setBeanClass(beanClass);
- }
- else {
- String beanClassName = getBeanClassName(element);
- if (beanClassName != null) {
- builder.getRawBeanDefinition().setBeanClassName(beanClassName);
- }
- }
- builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
- if (parserContext.isNested()) {
-
- builder.setScope(parserContext.getContainingBeanDefinition().getScope());
- }
- if (parserContext.isDefaultLazyInit()) {
-
- builder.setLazyInit(true);
- }
- doParse(element, parserContext, builder);
- return builder.getBeanDefinition();
- }
其中有一行:
- Class beanClass = getBeanClass(element);
getBeanClass是在TxAdviceBeanDefinitionParser中實現(xiàn)的,很簡單:
- @Override
- protected Class getBeanClass(Element element) {
- return TransactionInterceptor.class;
- }
至此,這個標簽解析的流程已經(jīng)基本清晰了。那就是:解析除了一個以TransactionInerceptor為classname的beandefinition并且注冊這個bean。剩下來要看的,就是這個TranscationInterceptor到底是什么?
看看這個類的接口定義,就明白了:
- public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable
這根本就是一個spring AOP的advice嘛!現(xiàn)在明白為什么事務(wù)的配置能通過aop產(chǎn)生作用了吧?
下面具體看看這個advice的advice:
- public Object invoke(final MethodInvocation invocation) throws Throwable {
-
-
-
- Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);
-
-
- final TransactionAttribute txAttr =
- getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
- final PlatformTransactionManager tm = determineTransactionManager(txAttr);
- final String joinpointIdentification = methodIdentification(invocation.getMethod());
-
- if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
-
- TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
- Object retVal = null;
- try {
-
-
- retVal = invocation.proceed();
- }
- catch (Throwable ex) {
-
- completeTransactionAfterThrowing(txInfo, ex);
- throw ex;
- }
- finally {
- cleanupTransactionInfo(txInfo);
- }
- commitTransactionAfterReturning(txInfo);
- return retVal;
- }
-
- else {
-
- try {
- Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
- new TransactionCallback<Object>() {
- public Object doInTransaction(TransactionStatus status) {
- TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
- try {
- return invocation.proceed();
- }
- catch (Throwable ex) {
- if (txAttr.rollbackOn(ex)) {
-
- if (ex instanceof RuntimeException) {
- throw (RuntimeException) ex;
- }
- else {
- throw new ThrowableHolderException(ex);
- }
- }
- else {
-
- return new ThrowableHolder(ex);
- }
- }
- finally {
- cleanupTransactionInfo(txInfo);
- }
- }
- });
-
-
- if (result instanceof ThrowableHolder) {
- throw ((ThrowableHolder) result).getThrowable();
- }
- else {
- return result;
- }
- }
- catch (ThrowableHolderException ex) {
- throw ex.getCause();
- }
- }
- }
哦,原來就是在這里控制了method invocation(spring aop是基于method的)!根據(jù)我們的配置,來決定
是不是對method使用事務(wù)。
至此,spring的事務(wù)管理已經(jīng)基本清晰了。就是解析出一個advice bean(of class : TransactionInterceptor)來,
然后在aop中配置pointcut和這個advice,就能產(chǎn)生作用了!
當然,這里沒有分析事物控制的細節(jié)以及spring aop的原理,這些在接下來的章節(jié)里面會慢慢補全~