众所周知, 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对象的.
可以看到配置的TransactionProxyFacotoryBean是FactoryBean<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 、ThrowsAdvice和Interceptor都是下面的分类标记接口, 将advice分为几个大类.
MethodInteceptor和MethodBeforeAdvice是对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.
TransactionInterceptor是Advice 下的MethodInteceptor实现.
ProxyFactory
在回首看TransactionProxyFactory#getObject & #afterPropertiesSet 方法, 可以看到这些类的使用.
AopProxy
通过上述ProxyFactory类图和AoppProxy的类图, 接合TransactionProxyFactoryBean的源码,基本可以明白产出Proxy代理实例.
现在进入Jdk / Cglib具体类实现中看Advisor是如何参与到Proxy生成过程的: JdkDynamicAopProxy和ObjenesisCglibAopProxy是jdk动态代理和cglib动态代理生成代理实例的Spring实现类; 想要明白Advisor是如何参与到Proxy生成的过程, 其实也就是如何将AdvisorSupport中的advisor翻译成Jdk Dynamic 或者Cglib需要的语言.
JdkDynamicAopProxy
重点: MethodInvocation是将advisors串联起来的关键, Advisor在MethodInvocation里面会转换成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);
}
}
MethodBeforeAdapter和MethodBeforeAdviceInteceptor就将MethodBeforeAdvice适配成MethodInteceptor.
到这里,我们基本就了解清楚了Spring中是如何实现JDK动态代理生成Proxy实例的.
CglibAopProxy
对于Cglib动态代理的实现, 其实和JDK动态代理的实现大致相同, 只不过在Cglib中实现的自己的MethodInvocation: CglibMethodInvocation.
如果有兴趣可以自行浏览源码实现.
Question
-
JdkDynamic代理中target和proxy这2个变量有什么区别?
-
MethodInvocation#proceed中的Return-Value是如何返回的
-
回头看: 如何在TransactionProxyFactoryBean中维护DB connection事务
-
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代理是如何完成事务传播以及事务控制的. 那么对于前面其他方式配置的事务,又是如何实现的.
- 对Dao配置TransactionProxyFactoryBean代理:单个Dao配置
- 使用父Dao配置TransactionProxyFactoryBean, 其他Dao继承父Dao
- BeanNameAutoProxyCreator配置自动拦截
- tx:advice + aop:config
- tx:annotation-driven 自动扫描注解
- Java-Config
1. **BeanNameAutoProxyCreator**: 对所有符合条件的bean自动创建Proxy代理, 代理的切面在interceptorName中配置, 这里就对应前面的事务切面TransactionInteceptor.
BeanNameAutoProxyCreator的自动拦截逻辑是通过实现BeanPostProcessor#postProcessBeforeInitialization方法来实现对#getBean复杂操作.
-
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