经过前面的学习,我们了解了Spring AOP的执行过程。
这里想提醒注意一个小问题,我们在对象的方法中调用该对象的另外一个方法会出现什么现象呢?

现象

  1. 定义对象方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class BusinessService implements IBusinessService{
    @Override
    public String sayHello(){
    System.out.println("hello");
    System.out.println("i want to say again");
    this.sayAgain();
    return "hello";
    }

    @Override
    public String sayAgain() {
    System.out.println("again");
    return "again";
    }
    }

sayHello 方法中调用了该对象的sayAgain方法。

  1. 配置aop

    1
    2
    3
    4
    5
    6
    7
    8
    <bean id="businessService" class="cn.sexycode.spring.study.chapter5.BusinessService"/>
    <bean id="logAspect" class="cn.sexycode.spring.study.chapter5.LogAspect"/>
    <bean class="cn.sexycode.spring.study.chapter5.BusinessBeforeAdvice"/>
    <aop:config>
    <aop:aspect id="log" ref="logAspect">
    <aop:before method="log" pointcut="execution(* cn.sexycode.spring.study.chapter5.BusinessService.*(..))"/>
    </aop:aspect>
    </aop:config>

BusinessService的每个方法调用前打印log

  1. 执行结果

    1
    2
    3
    4
    public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("sameobject.xml");
    applicationContext.getBean(IBusinessService.class).sayHello();
    }
1
2
3
4
log
hello
i want to say again
again

并没有想我们想象的那样在每个方法中打印log

原因在前面的文章中提到过,将执行到目标对象的方法sayHello时,这个时直接调用sayAgain方法时,跟代理对象没有关系了,所以是不会生效的。我们要弄清楚方法调用之所以能被拦截,就是因为我们调用的是代理对象的方法,而不是目标对象的方法。这跟子类重写父类的方法容易混淆,当我们重写之后,调用的是子类的方法。

解决方法

想要解决这个问题也很简单,思路就是在方法内部调用代理对象的方法就可以了。

  1. 暴露代理对象
  2. 将方法放到其他对象

暴露代理对象

Spring 给我们提供了一个工具类org.springframework.aop.framework.AopContext#currentProxy可以获取当前调用的代理对象。但是需要我们暴露出代理对象,如:<aop:aspectj-autoproxy expose-proxy="true">

将两个方法拆分到不同的对象中

这个很好理解,拆分出去后调用的是两个代理对象的方法,也就可以被拦截。