Spring代码分析(Bean调用,事宜,AOP)(一)

Spring代码分析(Bean调用,事务,AOP)(一)
首先要说的是,这篇文章是基于我的另外一篇文章(郁闷系列)让我郁闷的Spring事务回滚及对其它AOP操作的影响而来的。

在调试了半天后,终于无法忍受时间的流逝以及精神上的折磨(一次又一次的失败),把Spring的源码导进项目工程里,开始调试之路,下面结合Spring的源码说一下Spring事务的运行机理以及如果定义了其他AOP(Spring事务本身就是AOP的around实现)的实现方式。

首先给出一段配置代码:

<aop:config>
		<aop:pointcut id="logPointcut" expression="execution(* *..*Service.save*(..)) || execution(* *..*Service.update*(..)) || execution(* 

*..*Service.delete*(..))"/> 
		
		<aop:advisor pointcut="execution(* *..*Service.*(..))" advice-ref="txAdvice" order="2"/>
		<aop:advisor pointcut="execution(* *..*Service.save*(..)) || execution(* *..*Service.update*(..)) || execution(* *..*Service.delete*(..))" 

advice-ref="logAfterAdvice"/>
		
		<aop:aspect id="logAspect" ref="logInterceptor" order="1" >  
        	<aop:after-throwing  
            	pointcut-ref="logPointcut"    
            	method="serviceIntercept" />  
    	</aop:aspect>
		
	</aop:config>

上面的一段是aop的配置代码,其实很简单,第一个aop配置的切入点是Service层以save,update,delete开始的方法,作用是记录日志,当然了,你不想记录的时候,也是可以的,后面会有叙述。第二个aop的advisor就不用说了,事务的配置,第三个是异常拦截并记录日志的aop配置。针对上面的aop配置,我们就假设这里有一个部门的Service:

public interface DepartmentService{
	public void saveDepartment(departmentVO vo, LogVO LogVO);
}

DepartmentService的实现类我们就不写了,另外,我们假设在Action层(无论是struts或者是Webwork或者其他的MVC框架)来调用这个Service里的方法来保存部门的信息,下面我们来看一下整个过程Spring内部是如何运作的。

众所周知的,Spring对接口是使用jdk动态代理的,当我们从Action里调用Service里方法时,Spring会去执行DepartmentService的动态代理类JdkDynamicAopProxy,关于动态代理方面的知识,最近到处都是,都快审美疲劳了,看来什么都可以流行啊,如果那位不是很明白,可以网上搜索一下。ok,继续,看里面的invoke方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		.......
			// Get the interception chain for this method.
			List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
			}
			else {
				// We need to create a method invocation...
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}
	.........
}
从上面这段代码可以看出,getInterceptorsAndDynamicInterceptionAdvice是得到作用于要拦截方法(saveDepartment)上的所有的拦截器,并封装成一个List列表,而下面紧接会做一判断,如果没有配置拦截器,则不会创建一个方法调用,而直接调用目标代码执行,而如果有作用于改方法上的拦截器,则创建一个拦截方法调用,即
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
实际上代码
retVal = invocation.proceed();
中调用的方法proceed()即为ReflectiveMethodInvocation里的方法,我们看一下这个方法有什么作用:

public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

		Object interceptorOrInterceptionAdvice =
		    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
			    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

稍微一了解,就能看出,这是一个AOP拦截器的匹配操作,如果匹配上,则进行调用操作,通过该方法就能够得到所有配置的aop中那些是真正作用于该方法,另外注意的是代码:return proceed();明显的递归操作,会递归调用所有符合条件的拦截器操作。

仍旧以我们的代码为例,按照我们上面配置的,首先会是事务的拦截器被调用,即TransactionInterceptor,看此类的invoke方法:

public Object invoke(final MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be <code>null</code>.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.
		Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);

		// If the transaction attribute is null, the method is non-transactional.
		final TransactionAttribute txAttr =
				getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
		final String joinpointIdentification = methodIdentification(invocation.getMethod());

		if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);
			Object retVal = null;
			try {
				// This is an around advice: Invoke the next interceptor in the chain.
				// This will normally result in a target object being invoked.
				retVal = invocation.proceed();
			}
			catch (Throwable ex) {
				// target invocation exception
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
	.....

}

这个方法就是使用AOP进行声明式事务的实现代码,这里需要说明的是,首先是createTransactionIfNecessary方法,这个方法看名字就知道,在必要的情况下创建事务,我们进入这个方法会看到这样的一行代码:
status = getTransactionManager().getTransaction(txAttr);
这行代码说明从事务管理器得到一个事务,这里其实说来简单,其实深入的看一下代码还是蛮复杂的,假设我们项目使用的Spring+hibernate,那么自然我们使用Hibernate的事务,下面我们会就代码说明如何取的一个Hibernate事务,首先我们看AbstractPlatformTransactionManager的

getTransaction方法,这里提醒一下,如果你想弄懂Spring的事务的话,请先把这个方法里的代码搞明白,下面我们在这个方法里用中文将一些代码的含义标识出来:

public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
		Object transaction = doGetTransaction();

		// Cache debug flag to avoid repeated checks.
		boolean debugEnabled = logger.isDebugEnabled();
		if (debugEnabled) {
			logger.debug("Using transaction object [" + transaction + "]");
		}

		if (definition == null) {
			// Use defaults if no transaction definition given.
			definition = new DefaultTransactionDefinition();
		}

		if (isExistingTransaction(transaction)) {//这里判断当前是否存在事务
			// Existing transaction found -> check propagation behavior to find out how to behave.
			//在下面方法里,由于当前存在事务,那么需要判断当前拦截的方法在Spring配置文件中配置的propagation的值
			//如果是Never的话,则会抛出异常,因为当前已经存在事务
			//如果是REQUIRES_NEW,则会挂起当前事务,重新开启一个新事务
			//如果是NESTED,则创建一个savepoint,以便事务回滚的时候,可以回滚到该savepoint
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		// Check definition settings for new transaction.
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {//判断事务的失效时间(如果设置的话,默认是-1,不失效)
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		// No existing transaction found -> check propagation behavior to find out how to proceed.
		//没有事务存在,则检查propagation,目前基本都是使用的默认值,即REQUIRED
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		//如果下面条件满足,则新建一个事务
		else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
		    definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			Object suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			doBegin(transaction, definition);//新建一个事务
			boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
			return newTransactionStatus(
					definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
		}
		else {
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return newTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}
实际上AbstractPlatformTransactionManager类是个平台事务的抽象类,如果你使用的是Hibernate,那么取事务的时候得到就是Hiberante的事务,即通过

HibernateTransactionManager里doBegin方法得到一个Hibernate事务。看HibernateTransactionManager里doBegin方法里的一段代码:

// Register transaction timeout.
			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				if (hibernateSetTimeoutAvailable) {
					// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1
					// Applies to all statements, also to inserts, updates and deletes!
					hibTx = session.getTransaction();
					hibTx.setTimeout(timeout);
					hibTx.begin();
				}
				else {
					// Use Spring query timeouts driven by SessionHolder on Hibernate 3.0
					// Only applies to Hibernate queries, not to insert/update/delete statements.
					hibTx = session.beginTransaction();
					txObject.getSessionHolder().setTimeoutInSeconds(timeout);
				}
			}
			else {
				// Open a plain Hibernate transaction without specified timeout.
				hibTx = session.beginTransaction();
			}
是不是很熟悉啊,相信用过Hiberante的大侠,对session.beginTransaction();再熟悉不过了。至于启动事务,然后将该事务设置到一个session holder,可以看一下此方法下面的代码。

ok,至此,我们成功的开启一个事务,那么让我们回到TransactionInterceptor,既然事务已经开启,而事务aop又是一个around advice,那么下面就会调用目标代码执行:

retVal = invocation.proceed();


目标代码执行的过程中,如果没有异常抛出,则会提交事务:
commitTransactionAfterReturning(txInfo);
如果有异常抛出,则会根据情况来处理事务:
completeTransactionAfterThrowing(txInfo, ex);此方法里实现的即为我们经常提到的,如果是runtime异常事务会回滚,如果不是,则事务仍然会提交,看代码:

protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
		if (txInfo != null && txInfo.hasTransaction()) {
			if (logger.isDebugEnabled()) {
				logger.debug("Completing transaction for [" + txInfo.getJoinpointIdentification() +
						"] after exception: " + ex);
			}
			if (txInfo.transactionAttribute.rollbackOn(ex)) {
				try {
					this.transactionManager.rollback(txInfo.getTransactionStatus());
				}
				catch (RuntimeException ex2) {
					logger.error("Application exception overridden by rollback exception", ex);
					throw ex2;
				}
				catch (Error err) {
					logger.error("Application exception overridden by rollback error", ex);
					throw err;
				}
			}
			else {
				// We don't roll back on this exception.
				// Will still roll back if TransactionStatus.isRollbackOnly() is true.
				try {
					this.transactionManager.commit(txInfo.getTransactionStatus());
				}
				catch (RuntimeException ex2) {
					logger.error("Application exception overridden by commit exception", ex);
					throw ex2;
				}
				catch (Error err) {
					logger.error("Application exception overridden by commit error", ex);
					throw err;
				}
			}
		}
	}