Spring代码分析(Bean调用,事宜,AOP)(一)
Spring代码分析(Bean调用,事务,AOP)(一)
首先要说的是,这篇文章是基于我的另外一篇文章(郁闷系列)让我郁闷的Spring事务回滚及对其它AOP操作的影响而来的。
在调试了半天后,终于无法忍受时间的流逝以及精神上的折磨(一次又一次的失败),把Spring的源码导进项目工程里,开始调试之路,下面结合Spring的源码说一下Spring事务的运行机理以及如果定义了其他AOP(Spring事务本身就是AOP的around实现)的实现方式。
首先给出一段配置代码:
上面的一段是aop的配置代码,其实很简单,第一个aop配置的切入点是Service层以save,update,delete开始的方法,作用是记录日志,当然了,你不想记录的时候,也是可以的,后面会有叙述。第二个aop的advisor就不用说了,事务的配置,第三个是异常拦截并记录日志的aop配置。针对上面的aop配置,我们就假设这里有一个部门的Service:
DepartmentService的实现类我们就不写了,另外,我们假设在Action层(无论是struts或者是Webwork或者其他的MVC框架)来调用这个Service里的方法来保存部门的信息,下面我们来看一下整个过程Spring内部是如何运作的。
众所周知的,Spring对接口是使用jdk动态代理的,当我们从Action里调用Service里方法时,Spring会去执行DepartmentService的动态代理类JdkDynamicAopProxy,关于动态代理方面的知识,最近到处都是,都快审美疲劳了,看来什么都可以流行啊,如果那位不是很明白,可以网上搜索一下。ok,继续,看里面的invoke方法
稍微一了解,就能看出,这是一个AOP拦截器的匹配操作,如果匹配上,则进行调用操作,通过该方法就能够得到所有配置的aop中那些是真正作用于该方法,另外注意的是代码:return proceed();明显的递归操作,会递归调用所有符合条件的拦截器操作。
仍旧以我们的代码为例,按照我们上面配置的,首先会是事务的拦截器被调用,即TransactionInterceptor,看此类的invoke方法:
这个方法就是使用AOP进行声明式事务的实现代码,这里需要说明的是,首先是createTransactionIfNecessary方法,这个方法看名字就知道,在必要的情况下创建事务,我们进入这个方法会看到这样的一行代码:
getTransaction方法,这里提醒一下,如果你想弄懂Spring的事务的话,请先把这个方法里的代码搞明白,下面我们在这个方法里用中文将一些代码的含义标识出来:
HibernateTransactionManager里doBegin方法得到一个Hibernate事务。看HibernateTransactionManager里doBegin方法里的一段代码:
ok,至此,我们成功的开启一个事务,那么让我们回到TransactionInterceptor,既然事务已经开启,而事务aop又是一个around advice,那么下面就会调用目标代码执行:
目标代码执行的过程中,如果没有异常抛出,则会提交事务:
commitTransactionAfterReturning(txInfo);
如果有异常抛出,则会根据情况来处理事务:
completeTransactionAfterThrowing(txInfo, ex);此方法里实现的即为我们经常提到的,如果是runtime异常事务会回滚,如果不是,则事务仍然会提交,看代码:
首先要说的是,这篇文章是基于我的另外一篇文章(郁闷系列)让我郁闷的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; } } } }