Spring源码的一些理解---事务中的动态代理

spring 的事务和动态代理是息息相关的,也常常一不注意就事务失效,那么想弄明白失效的原因要从 spring 的动态代理说起

动态代理

先看下面的伪代码:

public class UserService {

	@AutoWired
	private OrderService orderService;

	public void test(){
	sout(orderService);
	}

}

然后我们在写一个 切面,具体的内容就是在 test() 方法执行前,输出随意的一段话,也就是我们常说的 aop。
那么当容器加载完成之后,我么从容器中 getBean(userService).test() 的执行流程是什么呢?

  1. 首先,我们从容器中拿到的是 最原始的普通的 userService 还是经过代理的 userServiceProxy 呢?是后者
  2. userServiceProxy 里面大体是什么样子的呢?
class userServiceProxy extends UserService{
	public void  test(){
		//aop的代码,我们这里是输出一句话
		sout(aop的代码);
		//然后就应该是原本test的逻辑了
		sout(orderService);
	}
}

因为没有接口,所以使用的是 cglib 进行的动态代理,也就是 父子类的形式,那么注意看 sout(orderService) ; 这样写是不对的,因为直接这么写或者写 super.test() 都不对,如果这么写,那么 orderService 是 null。这里要分清楚 我们继承的是 类,而不是对象。因为父类的 orderservice 是后面才附上的值,而不是在类初始化的时候就附上的,所以我们的子类,也就是代理类,直接用 super.test 是不行的 ,是拿不到 orderService的,所以我们需要使用 target,这个target就是父类产生的对象,也就是

class userServiceProxy extends UserService{

	private Object target;

	public void  test(){
		//aop的代码,我们这里是输出一句话
		sout(aop的代码);
		//然后就应该是原本test的逻辑了
		target.sout(orderService);
	}
}

这样才对。也就是说,虽然是动态代理,但是真正的逻辑还是在父类的,也就是没有动态代理的类的对象所执行
知道了这一点,那么现在来看 spring 的事务,spring的事务是声明式的,也就是 @Transcational 注解即可。如果是这么写的代码,没问题。

public class UserService {

	@AutoWired
	private OrderService orderService;

	@Transcational 
	public void test(){
	test方法的jdbc的增删改
	}

}

因为动态代理的原因,最终的代码会变成这样

class userServiceProxy extends UserService{

	private Object target;

	public void  test(){
		//aop的代码,我们这里是添加事务的代码,例如,将jdbc的链接的自动提交改为false
		con.setCommit(false)
		//然后就应该是原本test的逻辑了
		test方法的jdbc的增删改
	}
}

但是如果存在事物的传播行为,也就是如下:

public class UserService {

	@AutoWired
	private OrderService orderService;

	@Transcational 
	public void test(){
	test方法的jdbc的增删改
	a();
	}
	
	@Transcational 
	public void a(){
	a方法的jdbc的增删改
	}

}

test方法和a方法都加了 @Transcational 注解,现在我们从容其中取出userService,然后调用 userService.test 方法。会发现,如果代码报错的话,数据库并没有回滚,这是为什么呢?
其实还是刚才说的原因,我们看动态代理后的代码,如下,由于我们拿到的userService是动态代理后的对象那么他对 @Transcational 注解的处理仅限于test方法,至于test方法中,再去调用其他的方法,代理类是不会去处理其他方法上的 @Transcational 注解的,也就是说,处理的范围只限于test方法本身:

class userServiceProxy extends UserService{

	private Object target;

	public void  test(){
		//aop的代码,我们这里是添加事务的代码,例如,将jdbc的链接的自动提交改为false
		con.setCommit(false)
		//然后就应该是原本test的逻辑了
		target.test方法的jdbc的增删改
		//a的增删改呢?这里要注意,a的增删改是由最原始的那么对象,也就是父类的对象,执行的,也就是 target.a 执行的,可是上文说了,@Transcational 注解的处理的范围只限于test方法本身,所以a方法上面的 @Transcational 注解的,是没有人去处理的,相当与没写,这就是事务失效的原因
	}
}

你可能感兴趣的:(spring,java,mybatis)