多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
### spring aop嵌套调用问题 在使用 Spring AOP 的时候,我们从 IOC 容器中获取的 Service Bean 对象其实都是代理对象,而不是那些 Service Bean 对象本身,也就是说获取的并不是被代理对象或代理目标。当我在自己的 Service 类中使用 this 关键字嵌套调用同类中的其他方法时,由于 this 关键字引用的并不是该 Service Bean 对象的代理对象,而是其本身,故 Spring AOP 是不能拦截到这些被嵌套调用的方法的 当同一个类中对两个方法增强后,一个方法调用另外一个方法时,产生了嵌套调用,其中一个切面就会失效 具体代码: ~~~ public void hello() { System.out.println("Hello,IOC"); goodbye(); } public void goodbye() { System.out.println("Goodbye"); } @Pointcut("execution(public * io.github.dunwu.spring.core.aop.example.IOCServiceImpl.hello(..))") public void testAOP1(){ } @Around("testAOP1()") public Object around(ProceedingJoinPoint p){ System.out.println("around before testAOP1..."); Object o = null; try { o = p.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("around after testAOP1..."); return o; } @Pointcut("execution(public * io.github.dunwu.spring.core.aop.example.IOCServiceImpl.goodbye(..))") public void testAOP2(){ } @Around("testAOP2()") public void around(ProceedingJoinPoint p){ System.out.println("around before testAOP2..."); Object o = null; try { p.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("around after testAOP2..."); return o; } ~~~ 调用hello方法时,会发生什么呢? 只有hello方法被增强了,goodbye方法直接被调用,并没有被增强。输出如下: ~~~undefined around before testAOP1... Hello,IOC Goodbye around after testAOP1... ~~~ ** 为什么goodbye方法没有被增强 ** 这是因为hello方法被增强之后,invoke hello方法时,调用goodbye其实是调用this.goodbye方法,也就是原始方法而并不是被增强的方法 ### 原理 ``` public interface ICustomerService { public void doSomething1(); public void doSomething2(); } public class CustomerServiceImpl implements ICustomerService { public void doSomething1() { System.out.println("Inside CustomerServiceImpl.doSomething1()"); doSomething2(); } public void doSomething2() { System.out.println("Inside CustomerServiceImpl.doSomething2()"); } } public class CustomerServiceProxy implements ICustomerService { private ICustomerService customerService; public void setCustomerService(ICustomerService customerService) { this.customerService = customerService; } public void doSomething1() { doBefore(); customerService.doSomething1(); doAfter(); } public void doSomething2() { doBefore(); customerService.doSomething2(); doAfter(); } private void doBefore() { // 例如,可以在此处开启事务 System.out.println("do some important things before..."); } private void doAfter() { // 例如,可以在此处提交或回滚事务、释放资源等等 System.out.println("do some important things after..."); } } public class TestProxy { public static void main(String[] args) { // 创建代理目标对象。对于Spring来说,这一工作 // 是由Spring DI容器完成的。 ICustomerService serviceProxyTarget = new CustomerServiceImpl(); // 创建代理对象。对于Spring来说,这一工作 // 也是由Spring DI容器完成的。 CustomerServiceProxy serviceProxy = new CustomerServiceProxy(); serviceProxy.setCustomerService(serviceProxyTarget); ICustomerService serviceBean = (ICustomerService) serviceProxy; // 调用业务逻辑操作 serviceBean.doSomething1(); } } ``` 现在以调试方式运行这个应用,你会发现在 doSomething1() 中调用 doSomething2() 方法的时候并未去执行CustomerServiceProxy 类的 doBefore()、doAfter() 方法。再来看看这句关键代码:doSomething2(); 把它隐含的意思也表达出来吧:this.doSomething2(); 在CustomerServiceImpl类中this关键字表示的是当前这个CustomerServiceImpl类的实例。那程序当然就会去执行 CustomerServiceImpl 类中的 doSomething2() 方法了,而不会去执行 CustomerServiceProxy 类中的 doSomething2() 方法 ### 解决方案 1. 将自身注入到自身 ``` public class OneBean { @Resource private OneBean oneBean; public OneBean() { System.out.println("构造器OneBean加载..." + this); } public String say(String a) { System.out.println("say a=" + a); oneBean.say2(a); return a + a; } public String say2(String a) { System.out.println("say2 a=" + a); return a + a; } ``` 2. 使用AopContext.currentProxy()来操作 ``` public class OneBean { public OneBean() { System.out.println("构造器OneBean加载..." + this); } public String say(String a) { System.out.println("say a=" + a); ((OneBean)AopContext.currentProxy()).say2(a) ; return a + a; } public String say2(String a) { System.out.println("say2 a=" + a); return a + a; } } ```