1.概述
本文介绍在方法上开启声明式事务@Transactional后(使用InfrastructureAdvisorAutoProxyCreator创建jdk动态代理),springboot的调用该方法的过程;
2.结论(重点)
- 在方法开启声明式事务后,spring会为该对象创建动态代理。spring容器为该bean创建了JdkDynamicAopProxy实例(jdk动态代理方式);
- 每一个配置的切面对应一个PointcutAdvisor实例,包含切面和切面需执行的Interceptor(切面的额外逻辑)。所有切面的Interceptor组成拦截器链;
- 调用目标方法时会先调用Interceptor链,最后调用目标方法(原理和servlet过滤器链相同);
- 在实例的方法A里面直接调用同个实例的另一个方法B,不会经过动态代理的调用。所有在A上没有,但是在B上有的切面都不会生效;
3.过程
测试代码
TestProxyServiceImpl继承TestProxyService接口,test()方法开启了事务(@Transactional)。下面测试/testProx/t1调用TestProxyServiceImpl.test()的过程;
//**接口
public interface TestProxyService {
String test();
}
//**开启事务的类
@Slf4j
@Service("testProxyService")
public class TestProxyServiceImpl implements TestProxyService {
//**开启事务的方法
@Override
@Transactional
public String test() {
String rst = "测试代理被调用,时间:"+ LocalTime.now();
log.info(rst);
return rst;
}
}
//**调用的入口
@Slf4j
@RestController
@RequestMapping("/testProxy")
public class TestProxyController {
@Autowired
private TestProxyService testProxyService;
@Autowired
private BeanFactory beanFactory;
@GetMapping(value = "/t1")
public Object t1(String test) {
log.info(test);
this.testProxyService.test();
return test;
}
}
动态代理
本节通过实例查看spring创建的jdk动态代理对象,并简单介绍相关的主要接口。后面的章节会详细介绍每个接口的功能和主要实现;
A.JdkDynamicAopProxy
所有Jdk动态代理对象都是JdkDynamicAopProxy的实例,JdkDynamicAopProxy是Spring封装的jdk动态代理类,实现了InvocationHandler接口的invoke方法。增强逻辑都在JdkDynamicAopProxy的invoke中调用;
B.AdvisedSupport
AdvisedSupport是spring封装的动态代理配置基类,所有方式(包括jdk动态代理和cglib动态代理)的动态代理相关的配置、属性和额外逻辑都在此对象中(比如创建代理对象和调用代理逻辑)。本例实际是使用AdvisedSupport的子类ProxyFactory;
C.TargetSource
TargetSource是对代理前的原对象的封装,提供了getTargetClass方法,获取原对象的class对象。本例把原对象(TestProxyServiceImpl的实例)封装成了SingletonTargetSource;
D.AdvisedSupportListener
AdvisedSupportListener代理对象监听器可以监听代理对象的创建和属性变化,为一个列表。提供了两个方法,activated(代理对象第一次创建时调用)和adviceChanged(代理对象的属性变化时调用)。本例没有配置代理对象监听器;
E.Advisor
Advisor(顾问)是对Advice(通知)的封装,通常内部会持有一个Advice对象。其子接口PointcutAdvisor,添加了一个getPointcut(获取切入点)方法,封装一个切面和一个切面添加的额外逻辑。Advisor是一个列表,支持给一个对象/方法添加多个切面和额外逻辑。本例使用BeanFactoryTransactionAttributeSourceAdvisor,内部持有的切面为TransactionAttributeSourcePointcut,通知为TransactionInterceptor;
F.Advice
Advice(通知)是动态代理对象真正需要额外执行逻辑的封装(此接口才是真正添加的额外逻辑,前面的接口全是封装),常见的有BeforeAdvice(调用之前执行),AfterAdvice(调用之后执行)和Interceptor(调用前后执行)。本例是声明式事务,所以使用了TransactionInterceptor(事务拦截器),在调用前后处理数据库事务开启和提交的逻辑;
调用过程
A.调用开启声明式事务的目标方法
调用testProxyService.test()方法,实际上是调用JdkDynamicAopProxy的invoke方法;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
......
try {
//**处理equals & hashCode 和 AdvisedSupport方法调用
Object retVal;
//**获取代理前的原对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//**获取Interceptor列表
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
//**如果Interceptor列表为空,直接调用目标方法
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
//**调用Interceptor链(依次调用每个Interceptor)
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
//**处理返回值类型
return retVal;
} finally {
//**释放资源
}
}
B.反射调用Interceptor链
使用ReflectiveMethodInvocation.proceed进行反射调用Interceptor链;
- 每个Interceptor都必须调用ReflectiveMethodInvocation实例的proceed方法,以调用下一个Interceptor;
- proceed方法每次从Interceptor链取出一个Interceptor执行,直接到所有的Interceptor链被执行完成,最后执行目标方法;
public Object proceed() throws Throwable {
//**如果Interceptor链全部执行完成,则调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//**每次从Interceptor链取出一个Interceptor
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//**如果拦截器为InterceptorAndDynamicMethodMatcher,则根据规则进行匹配。匹配上了就调用对应的Interceptor,匹配不上就直接调用下一个Interceptor
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher dm) {
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 {
return proceed();
}
}
else {
//**调用Interceptor
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
C.事务处理&调用目标方法
使用TransactionInterceptor.invoke进行事务处理,在目标方法test()执行前开启事务,然后执行目标方法,最后提交事务;
- spring新增加了ReactiveTransactionManager(响应式事务管理器,非阻塞事务管理),没有具体实现;
- spring新增加了CallbackPreferringPlatformTransactionManager(允许传入TransactionCallback接口实例处理业务逻辑),没有具体实现;
public Object invoke(MethodInvocation invocation) throws Throwable {
//**获取目标class对象(代理前的原calss对象)
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
//**调用父类的方法(在事务中执行下一个Interceptor和目标方法)
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
//**调用Interceptor链中的下一个Interceptor
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
//**获取事务管理器
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final TransactionManager tm = determineTransactionManager(txAttr);
//**处理ReactiveTransactionManager(响应式事务管理器,非阻塞事务管理,没有具体实现)的逻辑
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
...
}
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
//**标准事务管理
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
//**在事务中执行下一个Interceptor和目标方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
//**发生异步后,如果配置了异常回滚则回滚事务,否则提交事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {//**清除事务信息
cleanupTransactionInfo(txInfo);
}
//**依赖vavr包的操作,vavr当前最新版本为2021年的0.10.4,很久没更新了(不知道是不是不更新了,暂不深究)
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
//**提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
//**处理CallbackPreferringPlatformTransactionManager(允许传入TransactionCallback接口实例处理业务逻辑,没有具体实现)的逻辑
else {
...
}
}
4.存在问题
在TestProxyService里面的test2()里面调用test(),不会经过JdkDynamicAopProxy的invoke调用,而是直接调用test()。所以test()的事务不会生效;
结论:在实例的方法A里面直接调用同个实例的另一个方法B,不会经过动态代理的调用。所有在A上没有,但是在B上有的切面都不会生效;
public class TestProxyServiceImpl implements TestProxyService {
@Override
@Transactional
public String test() {
String rst = "测试代理被调用,时间:"+ LocalTime.now();
log.info(rst);
return rst;
}
@Override
public String test2() {
String rst = "测试代理被调用2,时间:"+ LocalTime.now();
log.info(rst);
//**调用开启声明式事务的方法,不会开启事务
this.test();
return rst;
}
}