Self invocation存在的问题
假设我们有如下的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | @Service public class TestServiceImpl implements TestService { @Override public void saveAB() { this.saveA(); this.saveB(); } @Transactional @Override public void saveA() { System.out.println("saveA"); } @Transactional @Override public void saveB() { System.out.println("saveB"); } } |
还有如下的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @RunWith(SpringRunner.class) @SpringBootTest public class TestServiceTest { @Autowired private TestService testService; @Test public void test() { testService.saveAB(); testService.saveA(); testService.saveB(); } } |
在
为什么self invocation会存在问题?
首先我们必须要清楚Spring AOP是基于代理的,但是在介绍代理之前,先来看看没有代理时是怎么样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class SimplePojo implements Pojo { @Override public void foo() { System.out.println("foo"); this.bar(); } @Override public void bar() { System.out.println("bar"); } } |
1 2 3 4 5 6 7 | public class Main { public static void main(String[] args) { Pojo pojo = new SimplePojo(); pojo.foo(); } } |
执行
1 2 | foo bar |
当我们调用
接下来我们就看看调用代理的方法是怎样的。
我们修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class Main { public static void main(String[] args) { SimplePojo target = new SimplePojo(); ProxyFactory factory = new ProxyFactory(target); factory.addInterface(Pojo.class); factory.addAdvice(new MethodBeforeAdvice() { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("before invoking method"); } }); Pojo pojo = (Pojo) factory.getProxy(); pojo.foo(); } } |
执行
1 2 3 | before invoking method foo bar |
这里的pojo是一个代理,当我们调用
当调用
怎么解决?
Spring proxy self-invocation ? my2cents列出了很多种方法来解决这个问题,下面我只介绍我个人认为最简单的方法,我们将TestServiceImpl修改为如下所示(注意看注释)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | @Service public class TestServiceImpl implements TestService { private final TestService self; // 注入自身,一定要加上@Lazy public TestServiceImpl(@Lazy TestService self) { this.self = self; } @Override public void saveAB() { // 将this替换为self self.saveA(); self.saveB(); } @Transactional @Override public void saveA() { System.out.println("saveA"); } @Transactional @Override public void saveB() { System.out.println("saveB"); } } |
这个时候再执行
参考资料
- java - Spring @Transactional Annotation : Self Invocation - Stack Overflow
- https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-proxying
- java - Self injection with Spring - Stack Overflow