Spring事务的传播属性对开发者相当便利,但是Spring AOP使用wrap而非继承来实现代理,会使得同一个service中,方法A调用方法B时,无法保证方法B的事务传播属性。本文简单总结下有哪些方法可以解决这个问题:
xml配置中,做如下配置:
<aop:aspectj-autoproxy expose-proxy="true"/>
然后再service中调用本地方法时,使用如下方式:
((XXXService)AopContext.currentProxy()).xxxMethod(params);
Spring AOP基于代理模式和装饰器模式,使用包装的方式,将实际的service实例包装到代理类中,因此service方法中的this并不会感知代理对象,而事务是设置在代理对象上的。
不同于AOP,AspectJ使用加载时织入的方式,支持所有的pointcut,因此可以支持内部方法的事务设置。
在xml中作如下配置,即可使Spring使用AspectJ来支持事务:
<tx:annotation-driven mode="aspectj"/>
service代码里面无需任何改动。
使用如下方式手动注入service,然后再service中调用内部方法时,要显式的指定self.xxxmethod()。
public class UserService {
private UserService self;
// 不要使用基于构造器的注入
public void setSelf(UserService self) {
this.self = self;
}
"userService" class="your.package.UserService">
"self" ref="userService" />
...
这种方法的缺陷是,只支持singleton的类,不支持原型等其他类型的bean。
使用如下方式:
public class SBMWSBL {
private SBMWSBL self;
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
public void postContruct(){
self =applicationContext.getBean(SBMWSBL.class);
}
这种方式的缺陷和3是一样的。
这种方式稍微复杂一些,但是支持单例bean的循环依赖问题。
首先,自定义接口,表示需要注入自我bean的service:
public interface BeanSelfAware {
void setSelf(Object proxyBean);
}
其次,service要实现这个接口,并提供self的设置方法。
@Service
public class AServiceImpl4 implements AService, BeanSelfAware {//此处省略接口定义
private AService proxySelf;
public void setSelf(Object proxyBean) { //通过InjectBeanSelfProcessor注入自己(目标对象)的AOP代理对象
this.proxySelf = (AService) proxyBean;
}
@Transactional(propagation = Propagation.REQUIRED)
public void a() {
proxySelf.b();//调用代理对象的方法 这样可以执行事务切面
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void b() {
}
}
最后,提供配置类,实现BeanPostProcessor接口,一旦有bean被初始化,就判断他是否实现了我们的接口,如果实现了就调用设置方法,将代理bena注入进去。
@Component
public class InjectBeanSelfProcessor2 implements BeanPostProcessor, ApplicationContextAware {
private ApplicationContext context;
//① 注入ApplicationContext
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(!(bean instanceof BeanSelfAware)) { //② 如果Bean没有实现BeanSelfAware标识接口 跳过
return bean;
}
if(AopUtils.isAopProxy(bean)) { //③ 如果当前对象是AOP代理对象,直接注入
((BeanSelfAware) bean).setSelf(bean);
} else {
//④ 如果当前对象不是AOP代理,则通过context.getBean(beanName)获取代理对象并注入
//此种方式不适合解决prototype Bean的代理对象注入
((BeanSelfAware)bean).setSelf(context.getBean(beanName));
}
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}