[Spring]如何完成事务传播特性

628 阅读12分钟

众所周知, Spring的事务传播是通过切面来完成的, 具体到技术实现上,也就是通过动态代理技术实现的AOP来完成的事务传播. 

那么, Spring源码是怎么去实现的Spring事务传播特性? 在事务传播的时候是怎么知道当前是否存在是事务 ?如何回滚、提交事务 ? 如何挂起当前事务的 ?如何控制数据库Connection ? 

下面是需要理解整个Spring事务传播机制需要弄明白的地方:

1. Spring如何完成事务传播的控制

      ?: 如何操作数据库Connection

2.如何配置Spring事务的. 即如何创建数据库操作层的Proxy对象的

3.了解切面的执行逻辑, 如何获取Connection? 

4. 了解Spring AOP模型, 理解Advisor等类

Spring配置事务传播特性

 1.XML Bean配置代理基类: TransactionProxyFactoryBean

 <bean id="userDao"  
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">  
           <!-- 配置事务管理器 -->  
        <property name="transactionManager" ref="transactionManager" />     
        <property name="target" ref="userDaoTarget" />  
        <property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" />
        <!-- 配置事务属性 -->  
        <property name="transactionAttributes">  
            <props>  
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>  
        </property>  
    </bean> 

这是Spring最开始配置事务传播特性的方式, 就是需要对每个XML Dao Bean都需要配置一遍比较繁琐. 

可以采用下面XML Bean都共享代理基类的方式来避免对每个都配置代理基类. 

2.XML Bean共享代理基类

<bean id="transactionBase"  
            class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"  
            lazy-init="true" abstract="true">  
        <!-- 配置事务管理器 -->  
        <property name="transactionManager" ref="transactionManager" />  
        <!-- 配置事务属性 -->  
        <property name="transactionAttributes">  
            <props>  
                <prop key="*">PROPAGATION_REQUIRED</prop>  
            </props>  
        </property>  
    </bean>    
   
    <!-- 配置DAO -->
    <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
    <bean id="userDao" parent="transactionBase" >  
        <property name="target" ref="userDaoTarget" />   
    </bean>

使用了@Bean / @Repository 等注入管理bean之后, 对于bean的配置就没有地方设置代理类了. 下面就需要BeanNameAutoProxyCreator出马了, 能够根据指定beanName的bean创建代理. 

3. XML配置拦截器: BeanNameAtuoProxyCreator

 <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
        <property name="beanNames">  
            <list>  
                <value>*Dao</value>
            </list>  
        </property>  
        <property name="interceptorNames">  
            <list>  
                <value>transactionInterceptor</value>  
            </list>  
        </property>  
    </bean>  

BeanNameAutoProxyCreator仅能通过beanName来对bean创建代理, 对于AOP规定的一些其他的切点pointcut语法并不支持,比如: executeion='execution(* com.bluesky.spring.dao.*.*(..))' 等等.

使用<tx:advice> + <aop:config>来配置事务AOP切面

4. XML使用tx:advice + aop:config配置事务AOP切面

<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
    
    <aop:config>
        <aop:pointcut id="interceptorPointCuts"
            expression="execution(* com.bluesky.spring.dao.*.*(..))" />
        <aop:advisor advice-ref="txAdvice"
            pointcut-ref="interceptorPointCuts" />        
    </aop:config>   

对于<tx:advice> + <aop:config>配置的事务AOP切面, 还是不够灵活. 

下面就引入了 tx:annotation-driven + @Transactional,实现注解式事务. 只需要在需要事务传播的方法上加上@Trasactional注解即可完成事务传播. 

5. XML使用tx:annotation-driven配置注解事务 @Transactional

 <tx:annotation-driven transaction-manager="transactionManager"/>


@Transactional
@Component("userDao")
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
 
    public List<User> listUsers() {
        return this.getSession().createQuery("from User").list();
    }
}

上面的还是需要XML配置, 使用@EnableTransactionManagement  可以完成Java-config配置, 完全取消XML配置

6. Java-Config方式配置注解式事务

SpringBoot在Application启动类通过注解开启事务管理:

@EnableTransactionManagement 

// 启注解事务管理,等同于xml配置方式的 <tx:annotation-driven />

TransactionProxyFacotryBean

先从最简单的事务配置方式 TransactionProxyFacotryBean 来看Spring是怎么完成创建Proxy对象的. 

可以看到配置的TransactionProxyFacotoryBeanFactoryBean<Object>的子类, 所有在XML中的配置的最终的实例是通过[FactoryBean#getObject()](https://juejin.cn/editor/drafts/7087822320219193358)返回的.     

#getObject

        @Override
	public Object getObject() {
		if (this.proxy == null) {
			throw new FactoryBeanNotInitializedException();
		}
		return this.proxy;
	}

getObject()方法内容很简单,返回的就是proxy变量.  观察可以看到proxy变量是在afterPropertiesSet中完成实例化的. 

        @Override
	public void afterPropertiesSet() {
		if (this.target == null) {
			throw new IllegalArgumentException("Property 'target' is required");
		}
		if (this.target instanceof String) {
			throw new IllegalArgumentException("'target' needs to be a bean reference, not a bean name as value");
		}
		if (this.proxyClassLoader == null) {
			this.proxyClassLoader = ClassUtils.getDefaultClassLoader();
		}

		ProxyFactory proxyFactory = new ProxyFactory();

		if (this.preInterceptors != null) {
			for (Object interceptor : this.preInterceptors) {
				proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
			}
		}

		// Add the main interceptor (typically an Advisor).
		proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));

		if (this.postInterceptors != null) {
			for (Object interceptor : this.postInterceptors) {
				proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
			}
		}

		proxyFactory.copyFrom(this);

		TargetSource targetSource = createTargetSource(this.target);
		proxyFactory.setTargetSource(targetSource);

		if (this.proxyInterfaces != null) {
			proxyFactory.setInterfaces(this.proxyInterfaces);
		}
		else if (!isProxyTargetClass()) {
			// Rely on AOP infrastructure to tell us what interfaces to proxy.
			Class<?> targetClass = targetSource.getTargetClass();
			if (targetClass != null) {
				proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
			}
		}

		postProcessProxyFactory(proxyFactory);

		this.proxy = proxyFactory.getProxy(this.proxyClassLoader);
	}

在afterPropertiesSet()中可以看到就是通过Spring ProxyFactory来完成的事务aop proxy实例的创建.   

// Add the main interceptor (typically an Advisor).
proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));

在这段代码就是设置创建proxy代理实例的切面.  createMainInterceptor()AbstractSingletonProxyFactory的抽象方法, 在子类TransactionProxyFactoryBean中实现.  

TransactionProxyFactoryBean中就是TransactionInterceptor包装成advisor.

private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();   

@Override
protected Object createMainInterceptor() {
	this.transactionInterceptor.afterPropertiesSet();
	if (this.pointcut != null) {
		return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
	}
	else {
		// Rely on default pointcut.
		return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
	}
}

Spring AOP模型

Spring的传播是通过Spring  AopProxyFactory来创建的proxy实例. 那么我们就从这里来了解一下Spring AOP模型, 看看TransactionInterceptor是怎么样被织入的. 

TransactionInteceptor看Spring Aop模型

Advice

下面是我整理的Spring Aop中关于切面Advice的类图

Advice是顶层标记接口, BeforeAdvice 、AfterAdvice 、ThrowsAdviceInterceptor都是下面的分类标记接口, 将advice分为几个大类. 

MethodInteceptorMethodBeforeAdvice是对Spring AOP切面的接口定义.  TransactionInterceptor就是实现了MethodInterceptor接口. 

Advisor就是切面Advice的容器, 用来保存advice切面.  可以通过new xxxAdvisor( advice)advice切面包装成advisor. Advisor#getAdvice可以得到advice切面实例.  

Advice包装成Advisor的示例: (TransactionProxyFactoryBean#createMainInterceptor)

@Override
protected Object createMainInterceptor() {
	this.transactionInterceptor.afterPropertiesSet();
	if (this.pointcut != null) {
		return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
	}
	else {
		// Rely on default pointcut.
		return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
	}
}

可以看到会将 Advice: transactionInterceptor转换为 TransactionAttributeSourceAdvisor 或者DefaultPointcutAdvisor.     

TransactionInterceptorAdvice 下的MethodInteceptor实现. 

ProxyFactory

在回首看TransactionProxyFactory#getObject & #afterPropertiesSet 方法, 可以看到这些类的使用. 

AopProxy

通过上述ProxyFactory类图和AoppProxy的类图, 接合TransactionProxyFactoryBean的源码,基本可以明白产出Proxy代理实例. 

现在进入Jdk / Cglib具体类实现中看Advisor是如何参与到Proxy生成过程的:  JdkDynamicAopProxyObjenesisCglibAopProxy是jdk动态代理和cglib动态代理生成代理实例的Spring实现类;  想要明白Advisor是如何参与到Proxy生成的过程, 其实也就是如何将AdvisorSupport中的advisor翻译成Jdk Dynamic 或者Cglib需要的语言. 

JdkDynamicAopProxy

重点: MethodInvocation是将advisors串联起来的关键, AdvisorMethodInvocation里面会转换成MethodInterceptor或者InterceptorAndDynamicMethodMatcher.

下面来看MethodInvocation是如何应用到AopProxy里面的.

#getProxy

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
	if (logger.isTraceEnabled()) {
		logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
	}
	Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

Jdk动态代理的实现主要是看InvocationHandler的实现,在#getProxy中可以看到invocationHandler的实现就在JdKDynamicAopProxy中实现: Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

下面继续查看Jdk动态代理的InvocationHandler的实现内容: (下面是完整的invoke方法实现)

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			List<Object> 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.
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				retVal = proxy;
			}
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

跳过不重要的的内容, 来看具体的method.invoke的内容. 

// Get the interception chain for this method.
List<Object> 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.
	Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
	retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
	// We need to create a method invocation...
	MethodInvocation invocation =
			new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
	// Proceed to the joinpoint through the interceptor chain.
	retVal = invocation.proceed();
}

List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 将所有的advisor组成了一个链条.  

如果chain.isEmpty也就是没有advisor(没有切面), 则直接是对原始method方法的反射执行. 

如果chain.is not Empty, 则创建MethodInvocation实例来执行所有切面的代码和原始method的代码: 

// We need to create a method invocation...
MethodInvocation invocation =
			new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();

RelfectiveMethodInvocation

构造方法:

protected ReflectiveMethodInvocation(
			Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
			@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

	this.proxy = proxy;
	this.target = target;
	this.targetClass = targetClass;
	this.method = BridgeMethodResolver.findBridgedMethod(method);
	this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
	this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}

在构造器中传入了拦截器链, #proceed方法中就是如何执行拦截器(切面)链的具体实现, 内容稍微有点绕, 需要仔细思考一下

#proceed

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;
		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
		if (dm.methodMatcher.matches(this.method, 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);
	}
}

可以看到在#procced方法实现中, 将拦截器(切面)分为2类: InterceptorAndDynamicMethodMatcher 和 MethodInterceptor .  InterceptorAndDynamicMethodMatcher其实就是pointcut定义的切面, 需要根据"execute" 等语法定义决定切面是否匹配. 

可以看出来, #proceed的执行思路大致类似于遍历执行inteceptor, 最后再执行joinpoint内容: 切入的method: 

if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
}

那么在这里面没有循环代码它又是怎么实现遍历Inteceptor的? 它又是怎么实现before/after/round实现的.  这里就以MethodInteceptor举例, 较为简单, InterceptorAndDynamicMethodMatcher 其实也和MethodIntecptor大致一直, 只是多了匹配的内容. 

MethodInteceptor:

public interface MethodInterceptor extends Interceptor {

	Object invoke(MethodInvocation invocation) throws Throwable;

}

可以看到MethodInterceptor#invoke方法在执行的时候会将MethoInvocation实例带入进去. 

在TransactionIntercptor实现中可以看到对MethodInvocation#proceed的调用:

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

	// Adapt to TransactionAspectSupport's invokeWithinTransaction...
	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

通过MethodInvocation#proceed中调用methodInteceptor#invoke, 然后在MethodIntercptor#invoke方法中调用MethodInvocation#proceed的方式就可以完成整个拦截器(切面)链的遍历执行. 

那么又是如何实现before/after/round的执行的? 

如果是before, 在MethodInteceptor#invoke实现中只需要在invocation#proceed调用之前执行切面内容即可. 

类似, after只需要在invokcation#proceed调用之后执行切面内容即可. aroud也可以类推. 

这里对代码执行逻辑有点饶, 多看看多理解即可明白实现. 

MethodInteceptor链的构建

在回到JdkDynamicAopProxy中, 看看这个拦截器链(切面)是如何构建的:

// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

这里是将AdvisorSupport中的advisor都转为Inteceptor.

AdvisorSupport#getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	List<Object> cached = this.methodCache.get(cacheKey);
	if (cached == null) {
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
				this, method, targetClass);
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}

DefaultAdvisorChainFactory

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;

		for (Advisor advisor : advisors) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						match = mm.matches(method, actualClass);
					}
					if (match) {
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

可以看到根据advisor的类型的不同, 会做不同的处理. PointcutAdvisor会得到InterceptorAndDynamicMethodMatcher或者普通的Inteceptor. 

那么Advisor又是如何转换为Inteceptor的:AdvisorAdapterRegistry#getInterceptors

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
	List<MethodInterceptor> interceptors = new ArrayList<>(3);
	Advice advice = advisor.getAdvice();
	if (advice instanceof MethodInterceptor) {
		interceptors.add((MethodInterceptor) advice);
	}
	for (AdvisorAdapter adapter : this.adapters) {
		if (adapter.supportsAdvice(advice)) {
			interceptors.add(adapter.getInterceptor(advisor));
		}
	}
	if (interceptors.isEmpty()) {
		throw new UnknownAdviceTypeException(advisor.getAdvice());
	}
	return interceptors.toArray(new MethodInterceptor[0]);
}

可以看到根据Advisor中持有的Advice(切面)类型的不同会做不同的处理, 如果切面就是MethodInteceptor实现, 直接返回.   

如果不是MethodInteceptor的实现, 则通过AdvisorAdptor将Advice转换为MethodInteceptor实现. 

以BeforeAdvice为例:

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

	@Override
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof MethodBeforeAdvice);
	}

	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
		return new MethodBeforeAdviceInterceptor(advice);
	}

}

MethodBeforeAdapterMethodBeforeAdviceInteceptor就将MethodBeforeAdvice适配成MethodInteceptor

到这里,我们基本就了解清楚了Spring中是如何实现JDK动态代理生成Proxy实例的. 

CglibAopProxy

对于Cglib动态代理的实现, 其实和JDK动态代理的实现大致相同, 只不过在Cglib中实现的自己的MethodInvocation: CglibMethodInvocation. 

如果有兴趣可以自行浏览源码实现. 

Question

  1. JdkDynamic代理中target和proxy这2个变量有什么区别?

  2. MethodInvocation#proceed中的Return-Value是如何返回的

  3. 回头看: 如何在TransactionProxyFactoryBean中维护DB connection事务

  4. Methond#procced如何完成before/after/round

TransactionInteceptor

在前面明白了Spring AOP模型之后, 明白了如何获取到proxy实例, 也明白了Advice如何参与到Proxy实例的生成过程的. 在回头来看事务切面的实现TransactionInteceptor, 了解在TransactionInteceptor中如何获取当前事务, 挂起当前事务, 提交/回滚当前事务. 

#invoke

@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
	// Work out the target class: may be {@code null}.
	// The TransactionAttributeSource should be passed the target class
	// as well as the method, which may be from an interface.
	Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
	// Adapt to TransactionAspectSupport's invokeWithinTransaction...
	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

可以看到具体的事务传播控制在# invokeWithinTransaction中实现,  获取事务的代码:

// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

#createTransactionIfNecessary

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

		// If no name specified, apply method identification as transaction name.
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				public String getName() {
					return joinpointIdentification;
				}
			};
		}

		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
				status = tm.getTransaction(txAttr);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

可以看到是通过TransactionManager#getTransction获取的事务:

status = tm.getTransaction(txAttr);

进去到PlatformTransactionManager中可以看到在其中定义了#getTransaction #commit #rollback方法. 

TransactionManager类图:

在Abstract中实现了了对事务传播级别的控制,将事务的具体实现委托给具体的实现类,比如DatasourceTransactionManager实现对数据库Database的事务实现. 

DatasourceTransactionManager

在DatasourceTransactionManager中可以看到, 对于具体的事务控制实现是落实到数据库Connection上. 通过数据库Connection API实现commit / rollback. 

那么在DatasoueceTransactionManager中是如何获取上下文中的Connection的? 猜测是ThreadLocal. 

可以看到在DataSourceTransactionManager中使用TransactionSynchronizationManager来管理上线文Connection的.  进入TransactionSynchronizationManager实现中, 也可以看到确实是使用的ThreadLocal来维护的上线文Connection. 

private static final ThreadLocal<Map<Object, Object>> resources =      new NamedThreadLocal<>("Transactional resources");

public static Object getResource(Object key) {
	Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
	Object value = doGetResource(actualKey);
	if (value != null && logger.isTraceEnabled()) {
		logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +
				Thread.currentThread().getName() + "]");
	}
	return value;
}

private static Object doGetResource(Object actualKey) {
		Map<Object, Object> map = resources.get();
		if (map == null) {
			return null;
		}
		Object value = map.get(actualKey);
		// Transparently remove ResourceHolder that was marked as void...
		if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
			map.remove(actualKey);
			// Remove entire ThreadLocal if empty...
			if (map.isEmpty()) {
				resources.remove();
			}
			value = null;
		}
		return value;
	}

事务配置方式

前面已经了解了通过XML配置Bean代理是如何完成事务传播以及事务控制的.  那么对于前面其他方式配置的事务,又是如何实现的. 

  1. 对Dao配置TransactionProxyFactoryBean代理:单个Dao配置
  2. 使用父Dao配置TransactionProxyFactoryBean, 其他Dao继承父Dao
  3. BeanNameAutoProxyCreator配置自动拦截
  4. tx:advice + aop:config 
  5. tx:annotation-driven 自动扫描注解
  6. Java-Config

1. **BeanNameAutoProxyCreator**:  对所有符合条件的bean自动创建Proxy代理, 代理的切面在interceptorName中配置, 这里就对应前面的事务切面TransactionInteceptor.  

BeanNameAutoProxyCreator的自动拦截逻辑是通过实现BeanPostProcessor#postProcessBeforeInitialization方法来实现对#getBean复杂操作. 

  1. tx:advice + aop:config:  tx:advice中定义了切面, aop:config定义了piointcut和对应的切面.  在AopNamespaceHandler中定义了对aop:config标签的解析. 

    public class AopNamespaceHandler extends NamespaceHandlerSupport {

     /**
      * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
      * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
      * and '{@code scoped-proxy}' tags.
      */
     @Override
     public void init() {
     	// In 2.0 XSD as well as in 2.5+ XSDs
     	registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
     	registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
     	registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
    
     	// Only in 2.0 XSD: moved to context namespace in 2.5+
     	registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
     }
    

ConfigBeanDefinitionParser中向Spring BeanFactory中注入了AspectJAwareAdvisorAutoProxyCreator . 功能和前面的BeanNameAutoProxyCreator类似.

3. tx:annotation-driven 注解驱动事务:  TxNamespaceHandler

4. Java-Config: 注入了AnnotationAwareAspectJAutoProxyCreator