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>
public interface DepartmentService{public void saveDepartment(departmentVO vo, LogVO LogVO);}
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);}}
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 exceptioncompleteTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}commitTransactionAfterReturning(txInfo);return retVal;}.....}
status = getTransactionManager().getTransaction(txAttr);这行代码说明从事务管理器得到一个事务,这里其实说来简单,其实深入的看一下代码还是蛮复杂的,假设我们项目使用的Spring+hibernate,那么自然我们使用Hibernate的事务,下面我们会就代码说明如何取的一个Hibernate事务,首先我们看AbstractPlatformTransactionManager的
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,以便事务回滚的时候,可以回滚到该savepointreturn 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,目前基本都是使用的默认值,即REQUIREDif (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的事务,即通过
// 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,可以看一下此方法下面的代码。
retVal = invocation.proceed();
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;}}}}