Spring传播行为内部方法不起作用(2)

落爺英雄遲暮 提交于 2019-12-30 17:35:52

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

在使用Spring的注解事务时候,我们发现内部方法声明的事务不起作用,而是决定于外部方法注解的事务。到底是真不起作用,还是我们Spring的事务注解机制理解错了,导致误用了。下面我们看两个例子:

 

测试类:

 

 
  1. package com.aop;

  2.  
  3. import org.springframework.beans.factory.BeanFactory;

  4. import org.springframework.context.support.ClassPathXmlApplicationContext;

  5.  
  6. import com.thread.service.IBaseFacadeService;

  7.  
  8.  
  9. //@RunWith(SpringJUnit4ClassRunner.class)

  10. //@ContextConfiguration(locations = { "classpath:/spring-ibatis.xml", "classpath:/spring-jdbctemplate.xml" })

  11. public class TestStudentDao {

  12.  
  13. public static void main(String[] args) {

  14. try {

  15. BeanFactory factory = new ClassPathXmlApplicationContext("spring-jdbctemplate.xml");

  16. IBaseService service = (IBaseService) factory.getBean("businessSerivce");

  17.  
  18. service.doA();

  19. } catch (Exception e) {

  20. // TODO Auto-generated catch block

  21. e.printStackTrace();

  22. }

  23. }

  24. }

 

 

第一例子:内部方法事务不起作用:

 

 
  1. package com.aop;

  2.  
  3. import org.springframework.aop.support.AopUtils;

  4. import org.springframework.beans.factory.annotation.Autowired;

  5. import org.springframework.stereotype.Service;

  6. import org.springframework.transaction.annotation.Isolation;

  7. import org.springframework.transaction.annotation.Propagation;

  8. import org.springframework.transaction.annotation.Transactional;

  9.  
  10. import com.entity.Student;

  11.  
  12. @Service("businessSerivce")

  13. public class BusinessServiceImpl implements IBaseService {

  14.  
  15. @Autowired

  16. IStudentDao studentDao;

  17.  
  18. @Override

  19. @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)

  20. public String doA() throws Exception {

  21. Student st = new Student();

  22. st.setId(1);

  23. st.setSex("girl");

  24. st.setUsername("zx");

  25. studentDao.insertStudent(st);

  26.  
  27. System.out.println(this);

  28. System.out.println("是否是代理调用,AopUtils.isAopProxy(this) : " + AopUtils.isAopProxy(this));

  29. System.out.println("是否是cglib类代理调用,AopUtils.isCglibProxy(this) : " + AopUtils.isCglibProxy(this));

  30. System.out.println("是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(this) : " + AopUtils.isJdkDynamicProxy(this));

  31.  
  32. this.doB();

  33. int i = 1 / 0;// 抛出异常,doB()的事务事务回滚

  34. return "success";

  35. }

  36.  
  37. @Override

  38. @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)

  39. public String doB() throws Exception {

  40. Student st = new Student();

  41. st.setId(2);

  42. st.setSex("girl");

  43. st.setUsername("zx2");

  44. studentDao.insertStudent(st);

  45.  
  46. return "success";

  47. }

  48.  
  49. }

测试类执行结果:

 

com.aop.BusinessServiceImpl@5a47cf7
是否是代理调用,AopUtils.isAopProxy(this) : false
是否是cglib类代理调用,AopUtils.isCglibProxy(this) : false
是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(this) : false
java.lang.ArithmeticException: / by zero


 

从测试类执行结果可以看到,我们没有成功插入数据。理论来说方法doB()使用Propagation.REQUIRES_NEW传播行为,我们应该在数据库中插入姓名为zx2的数据,但是却是事与愿违,程序没有按照我们想要的方向走,不急,我们再看下面的例子:

第二例子:内部方法事务起作用

 

 
  1. package com.aop;

  2.  
  3. import org.springframework.aop.support.AopUtils;

  4. import org.springframework.beans.BeansException;

  5. import org.springframework.beans.factory.annotation.Autowired;

  6. import org.springframework.context.ApplicationContext;

  7. import org.springframework.context.ApplicationContextAware;

  8. import org.springframework.stereotype.Service;

  9. import org.springframework.transaction.annotation.Isolation;

  10. import org.springframework.transaction.annotation.Propagation;

  11. import org.springframework.transaction.annotation.Transactional;

  12.  
  13. import com.entity.Student;

  14.  
  15. @Service("businessSerivce")

  16. public class BusinessServiceImpl implements IBaseService,ApplicationContextAware {

  17.  
  18. @Autowired

  19. IStudentDao studentDao;

  20.  
  21. @Autowired

  22. ApplicationContext context;

  23.  
  24.  
  25. @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)

  26. public String doA() throws Exception {

  27. Student st = new Student();

  28. st.setId(1);

  29. st.setSex("girl");

  30. st.setUsername("zx");

  31. studentDao.insertStudent(st);

  32. //BusinessServiceImpl service1 = (BusinessServiceImpl)context.getBean(IBaseService.class);

  33. BusinessServiceImpl service = (BusinessServiceImpl)context.getBean("businessSerivce");

  34. //System.out.println(service1);

  35. System.out.println(service);

  36. System.out.println("是否是代理调用,AopUtils.isAopProxy(service) : " + AopUtils.isAopProxy(service));

  37. System.out

  38. .println("是否是cglib类代理调用,AopUtils.isCglibProxy(service) : " + AopUtils.isCglibProxy(service));

  39. System.out.println("是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(service) : "

  40. + AopUtils.isJdkDynamicProxy(service));

  41.  
  42. // 使用代理调用方法doB()

  43. service.doB();

  44.  
  45. int i = 1 / 0;// 抛出异常,doB()的事务事务回滚

  46. return "success";

  47. }

  48.  
  49.  
  50. @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)

  51. public String doB() throws Exception {

  52. Student st = new Student();

  53. st.setId(2);

  54. st.setSex("girl");

  55. st.setUsername("zx2");

  56. studentDao.insertStudent(st);

  57.  
  58. return "success";

  59. }

  60.  
  61.  
  62. @Override

  63. public void setApplicationContext(ApplicationContext arg0) throws BeansException {

  64. context = arg0;

  65.  
  66. }

  67.  
  68. }

测试类执行结果:

 

com.aop.BusinessServiceImpl@7b619bbf
是否是代理调用,AopUtils.isAopProxy(service) : true
是否是cglib类代理调用,AopUtils.isCglibProxy(service) : true
是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(service) : false
java.lang.ArithmeticException: / by zero

从执行结果来看,数据库中插入了一条数据,而这也正是我们想要的结果,数据库中插入的是doB()方法执行的结果,doA()执行结果被回滚了。

 

例一和例二有什么区别吗?我们来看打印出来的日志,例一中打印出调用doB()方法的对象this不是代理对象,而是代理目标对象。而例二调用doB()方法的对象service是代理对象,不是代理目标对象。最后例一没有我们达到我们的目的,而例二达到了我们目的。为什么代理目标对象执行doB()方法,声明在自己上面的事务就失效了,而代理对象执行doB()方法就成功了呢?这是因为spring在扫描所有类中@Transaction标记的方法的所有类,是通过代理对象植入事务这个特殊的前置增强(advise)的,而不是在代理目标对象上植入增强(advise)的。所以最后就出现了我们上面的两种结果。

 

注意我们这里使用的是Cglib动态代理(类代理)

所以我们在类BusinessServiceImpl中强制转换使用类强制转换

 

BusinessServiceImpl service = (BusinessServiceImpl)context.getBean("businessSerivce");

但是如果我们使用jdk动态代理<aop:aspectj-autoproxy proxy-target-class=false/>

那我们就得使用接口强制转换:

 

IBaseService service = (IBaseService)context.getBean("businessSerivce");
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!