类中有两个方法都有切面,如果在一个有切面的方法中,用this.调用另一个有切面的方法,会使被调用方法aop失效.
因为aop是基于接口或者是基于类创建代理,而不是基于方法创建代理
this指的是当前对象,当前对象是类,而不是代理类.
不想失效,就把类本身注入进类里,通过ioc容器调用类,这样就能生成代理类,就不会失效了
因为事务是用aop动态代理实现的,我们就测试一下事务失效的例子.
public interface AnalysisService {
void deleteAnalysisRole(int analysisRuleId);
void deleteAnalysisParam(int analysisRuleId);
}
@Service
public class AnalysisServiceImpl implements AnalysisService {
@Autowired
private AnalysisMapper analysisMapper;
@Autowired
private AnalysisService analysisService;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void deleteAnalysisRole(int analysisRuleId) {
//测试1 analysisService.deleteAnalysisParam(analysisRuleId);
//测试2 this.deleteAnalysisParam(analysisRuleId);
analysisMapper.deleteAnalysisRole(analysisRuleId);
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void deleteAnalysisParam(int analysisRuleId) {
analysisMapper.deleteAnalysisParameter(analysisRuleId);
}
}
实现类中的deleteAnalysisRole方法用于删除解析器与其参数( 解析器与解析器参数是两张表),
原方法删除解析器和其参数是在一个事务里,要么同时成功要么回滚.
但为了测试,把删除解析器与删除参数写在两个方法里,而且删除参数这个方法单独开一个事务(Propagation.REQUIRES_NEW 新建一个事务).
为了验证this.调用有切面的方法会不会失效,想了下边一个测试方法:
1 对照组:
- 流程:
解注测试1, 即用注入的service来调用删除参数的方法
analysisMapper.deleteAnalysisRole(analysisRuleId) 的sql里写错,让程序产生runtime异常,事务回滚,
用controller层调用service执行删除.
- 结果:
参数表对应的行删除成功,解析器表对应的行删除失败.
- 分析:
aop拦截了用注入的接口调用实现类的删除参数方法,删除参数方法是一个新建的事务,事务成功提交.
而删除规则的方法由于产生异常,事务回滚,删除失败.
2 实验组:
- 流程:
解注测试2,用this来调用本类删除参数方法
analysisMapper.deleteAnalysisRole(analysisRuleId) 的sql里写错,让程序产生runtime异常,事务回滚,
用controller层调用service执行删除.
注意:
- 结果:
参数表和解析器表都删除失败.
- 分析
是因为this是当前对象.删除参数是类调用的方法,aop没有切入内部调用的方法,没有生成动态代理类
没有生成代理类就没有实现事务,导致删除参数方法不能新建事务,于是加入了调用方法的事务中,随着异常一块回滚.
注意:
1.删除参数方法要写在删除规则前面,如果写在后面,运行时因为规则抛出异常,运行不到删除参数就会回滚,导致测试没有意义.
2.如果注入的是实现类自己
@Autowired
private AnalysisServiceImpl analysisServiceImpl;
也不会导致aop失效,注入自己也生成了代理类.