假如在一个service中,有A()和B()两个方法,假如A方法没有添加事务注解,B方法有添加事务注解,如果在A方法中调用B方法,那B方法并不会以事务方式运行,这是因为,在调用A()方法的时候,会判断这个方法是否需要有通知方法(或者说是否有切面作用于方法上)如果没有,就不会以代理对象的方式调用运行,在A调用B的时候,其实就是内部方法调用,所以B方法的事务并不会生效
如果我们要让B方法的事务生效,那就可以在A()方法中,调用B方法的时候,通过AopContext.currentProxy().B()的方式来调用,这样B方法的事务就会生效
//@Transactional
public void testNoTrans(){
System.out.println("这是非事务方法");
testTx();
}
@Transactional(rollbackFor = NullPointerException.class,propagation = Propagation.REQUIRES_NEW)
public void testTx() {
OperChannel updateOperChannel = new OperChannel();
updateOperChannel.setOperChannelId("7200");
updateOperChannel.setOperChannelName("河南微信-02");
operchannelDao.updateOperChannel(updateOperChannel);
System.out.println("测试信息");
// otherService.testUpdateOther();
OperChannel operChannelById = operchannelDao.getOperChannelById(1);
System.out.println(operChannelById.toString());
System.out.println(operChannelById.getOperChannelName());
}

这里可以看到,在调用的时候,发现此时的OperChannelService只是一个简单的对象,也可以通过在代码中,加上一行 “int i = 10/0”,来看事务是否回滚,此时事务是不会回滚的
如果把调用testTx()的代码,改成:
OperChannelService operChannelService = (OperChannelService) AopContext.currentProxy();
operChannelService.testTx();
此时会发现,事务已经生效了

AopContext既然可以获取到代理对象,那就表示,一定在某一个地方,把代理对象设置到了内存中
可以通过org.springframework.aop.framework.AopContext#currentProxy获取到当前的代理对象,然后通过这个代理对象,调用目标方法
这样,就可以以事务方法运行
private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<>("Current AOP proxy");
public static Object currentProxy() throws IllegalStateException {
Object proxy = currentProxy.get();
if (proxy == null) {
throw new IllegalStateException(
"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");
}
return proxy;
}
通过上面的方法,可以发现,在调用currentProxy()方法的时候,实际上是尝试去threadLocal中获取一个对象,然后返回,这里既然可以在这里取到,那一定是在某一个地方,向ThreadLocal中设置了一个对象
设置代理对象到threadlocal中:
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
在目标方法被调用的时候,会被这里的拦截器所拦截,在这里的intercept()方法中,有一段及其重要的代码
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
@Nullable
static Object setCurrentProxy(@Nullable Object proxy) {
Object old = currentProxy.get();
if (proxy != null) {
currentProxy.set(proxy);
}
else {
currentProxy.remove();
}
return old;
}
我们知道,在使用AopContext对象时,一定有一个前提,就是要在配置类上加上@EnableAspectJAutoProxy(exposeProxy = true),并且把exposeProxy设置TRUE,是因为在上面这段代码中,会判断这个参数是否为TRUE,只有在为true的情况下,才会在AopContext对象中,把当前的proxy代理对象设置到ThreadLocal中
所以,以上就是AopContext对象的原理
所以,总结来看,如果使用了AopContext对象,针对上面在非事务方法中,调用事务方法的流程是这样的:
如果没有使用AopContext对象: