先结合源码部分看一下执行流程,然后说一下解决方案(本列使用cglib代理,jdk动态代理类似)
话不多说,先看一下代理拦截器方法:
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;//这是咱们的目标类被各种切面封装后的代理对象
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {//很重要,设置了暴露代理才会执行下一步内容
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);//设置代理,并保存旧代理(1)
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);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);//拦截器链
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {//没有拦截器
// 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 = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...//咱们事务执行这里
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);//重新设置自己的代理类
}
}
}
进一步解析(1)处的内容:
public final class AopContext {
//使用threadlocal存储代理对象
private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<>("Current AOP proxy");
private AopContext() {
}
//可以在任何地方通过threadlocal获取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;
}
//设置代理时,放到threadlocal中
@Nullable
static Object setCurrentProxy(@Nullable Object proxy) {
Object old = currentProxy.get();
if (proxy != null) {
currentProxy.set(proxy);
}
else {
currentProxy.remove();
}
return old;
}
}
通过上面的源码分析,
1.开启暴露代理
2.我们可以直接通过AopContext 获取到Proxy对象,从而调用上面被各种切面织入的方法,进而实现代理.
理论不如实践,进行一下对比springboot环境:
开启暴露代理:@EnableAspectJAutoProxy(exposeProxy = true)
这一部分是事务不生效实例:
@Service
public class TranService{
@Autowired
private TranDao tranDao;
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public void add() {
User aaa = new User();
aaa.setAge(22);
aaa.setCtime(new Date());
aaa.setUserId(2);
aaa.setUserName("aaa");
tranDao.save(aaa);
try {
b();
}catch (Exception e){
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
public void b() {
User aaa = new User();
aaa.setAge(33);
aaa.setCtime(new Date());
aaa.setUserId(3);
aaa.setUserName("bbb");
tranDao.save(aaa);
throw new RuntimeException("111");
}
}
说明一下上面的代码:按spring事务的规则,调用add()方法士应该开启一个事务,然后b()也加了事务,推断出想在b()调用时,开启单独事务,那么期望结果是a()提交,b()回滚
2019-07-17 21:26:04.623 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.example.demotran.tran.TranService.add]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Throwable
2019-07-17 21:26:04.623 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(76567159<open>)] for JPA transaction
2019-07-17 21:26:04.623 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@255421fa]
2019-07-17 21:26:04.639 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(76567159<open>)] for JPA transaction
2019-07-17 21:26:04.639 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction
Hibernate: select user0_.user_id as user_id1_0_0_, user0_.age as age2_0_0_, user0_.ctime as ctime3_0_0_, user0_.user_name as user_nam4_0_0_ from t_user user0_ where user0_.user_id=?
2019-07-17 21:26:04.717 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(76567159<open>)] for JPA transaction
2019-07-17 21:26:04.717 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction
Hibernate: select user0_.user_id as user_id1_0_0_, user0_.age as age2_0_0_, user0_.ctime as ctime3_0_0_, user0_.user_name as user_nam4_0_0_ from t_user user0_ where user0_.user_id=?
java.lang.RuntimeException: 111
at com.example.demotran.tran.TranService.b(TranService.java:42)
......
2019-07-17 21:26:04.717 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2019-07-17 21:26:04.717 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(76567159<open>)]
//两条数据都进行了插入,没有回滚
Hibernate: insert into t_user (age, ctime, user_name, user_id) values (?, ?, ?, ?)
Hibernate: insert into t_user (age, ctime, user_name, user_id) values (?, ?, ?, ?)
2019-07-17 21:26:04.733 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(76567159<open>)] after transaction
看一下符合期望的编码:
package com.example.demotran.tran;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@Service
public class TranService{
@Autowired
private TranDao tranDao;
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public void add() {
User aaa = new User();
aaa.setAge(22);
aaa.setCtime(new Date());
aaa.setUserId(2);
aaa.setUserName("aaa");
tranDao.save(aaa);
try {
TranService tranService = (TranService) AopContext.currentProxy();
tranService.b();
}catch (Exception e){
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
public void b() {
User aaa = new User();
aaa.setAge(33);
aaa.setCtime(new Date());
aaa.setUserId(3);
aaa.setUserName("bbb");
tranDao.save(aaa);
throw new RuntimeException("111");
}
}
看一下执行日志:
//开启事务
2019-07-17 21:28:34.108 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.example.demotran.tran.TranService.add]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Throwable
2019-07-17 21:28:34.108 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(176172822<open>)] for JPA transaction
2019-07-17 21:28:34.124 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@58c34766]
2019-07-17 21:28:34.124 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(176172822<open>)] for JPA transaction
2019-07-17 21:28:34.124 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction
Hibernate: select user0_.user_id as user_id1_0_0_, user0_.age as age2_0_0_, user0_.ctime as ctime3_0_0_, user0_.user_name as user_nam4_0_0_ from t_user user0_ where user0_.user_id=?
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(176172822<open>)] for JPA transaction
//挂起了当前事务
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Suspending current transaction, creating new transaction with name [com.example.demotran.tran.TranService.b]
//开启了一个新的实体管理器为事务操作
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(1157613382<open>)] for JPA transaction
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@1e1d8bf4]
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1157613382<open>)] for JPA transaction
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction
Hibernate: select user0_.user_id as user_id1_0_0_, user0_.age as age2_0_0_, user0_.ctime as ctime3_0_0_, user0_.user_name as user_nam4_0_0_ from t_user user0_ where user0_.user_id=?
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Initiating transaction rollback
//回滚了事务
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Rolling back JPA transaction on EntityManager [SessionImpl(1157613382<open>)]
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(1157613382<open>)] after transaction
//重启了当前事务
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Resuming suspended transaction after completion of inner transaction
java.lang.RuntimeException: 111
at com.example.demotran.tran.TranService.b(TranService.java:41)
......
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(176172822<open>)]
//最终只有一条数据插入库中
Hibernate: insert into t_user (age, ctime, user_name, user_id) values (?, ?, ?, ?)
2019-07-17 21:28:34.186 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(176172822<open>)] after transaction
好了,今天就到这里.如果你有更好的方法,敬请留言,相互学习.
本文探讨了Spring事务中this调用如何生效的问题,通过源码分析和实际例子展示了在启用@EnableAspectJAutoProxy(exposeProxy = true)的情况下,如何利用AopContext获取代理对象,实现方法间的事务隔离。示例代码展示了一种符合预期的事务管理方式,并给出了执行日志,以帮助读者理解事务处理机制。
1481

被折叠的 条评论
为什么被折叠?



