Spring AOP not working for method call inside anot

2019-01-04 09:56发布

There are two methods defined in ABC.java

public void method1(){
   .........
   method2();
  ...........
}


public void method2(){
  ...............
  ...............  
}

I want to have AOP on call of method2.So, I created one class,AOPLogger.java,having aspect functionality provided in a method checkAccess
In configuration file, I did something like below

<bean id="advice" class="p.AOPLogger" />
<aop:config>
  <aop:pointcut id="abc" expression="execution(*p.ABC.method2(..))" />
  <aop:aspect id="service" ref="advice">
    <aop:before pointcut-ref="abc" method="checkAccess" />          
  </aop:aspect>
</aop:config>

But when my method2 is called, AOP functionality is not getting invoked i.e. checkAccess method is not getting invoked of AOPLogger class.

Any thing i am missing?

9条回答
Melony?
2楼-- · 2019-01-04 10:18

Using @Autowired it works. Instead of calling the inner method as this.method(), you can do:

@Autowired
Foo foo;

and then calling:

foo.method2();
查看更多
虎瘦雄心在
3楼-- · 2019-01-04 10:20

As indicated in the Spring docs, chapter 5.6.1 Understanding AOP proxies, there is another way you can do:

public class SimplePojo implements Pojo {

    public void foo() {
        // this works, but... gah!
        ((Pojo) AopContext.currentProxy()).bar();
    }

    public void bar() {
        // some logic...
    }
}

Although the author doesn't recommand this way. Because:

This totally couples your code to Spring AOP, and it makes the class itself aware of the fact that it is being used in an AOP context, which flies in the face of AOP. It also requires some additional configuration when the proxy is being created.

查看更多
疯言疯语
4楼-- · 2019-01-04 10:21

I had the same kind of problem and I overcame by implementing Spring's ApplicationContextAware,BeanNameAware and implementing corresponding methods as below.

class ABC implements ApplicationContextAware,BeanNameAware{

      @Override
      public void setApplicationContext(ApplicationContext ac) throws BeansException {
          applicationContext=ac;
      }

      @Override
      public void setBeanName(String beanName) {
          this.beanName=beanName;
      }
      private ApplicationContext applicationContext;
      private String beanName;
}

then I replaced this. with ((ABC) applicationContext.getBean(beanName)). while calling the methods of the same class. This ensures that calls to methods of the same class happen through the proxy only.

So method1() changes to

 public void method1(){
    .........
    ((ABC) applicationContext.getBean(beanName)).method2();
    ...........
  }

Hope this helps.

查看更多
仙女界的扛把子
5楼-- · 2019-01-04 10:21

You can do self-injection this way so that this class can be used outside Spring application.

@Component
public class ABC {

    @Resource
    private ABC self = this;

    public void method1() {
        self.method2();
    }

    public void method2() {

    }

}
查看更多
淡お忘
6楼-- · 2019-01-04 10:24

It can be done by self injection usage. You can call inner method through injected instance:

@Component
public class Foo {
    @Resource
    private Foo foo;

    public void method1(){
        ..
        foo.method2();
        ..
    }
    public void method2(){
        ..
    }
}

Since Spring 4.3 you also can do it using @Autowired.

As of 4.3, @Autowired also considers self references for injection, i.e. references back to the bean that is currently injected.

查看更多
何必那么认真
7楼-- · 2019-01-04 10:27

The aspect is applied to a proxy surrounding the bean. Note that everytime you get a reference to a bean, it's not actually the class referenced in your config, but a synthetic class implementing the relevant interfaces, delegating to the actual class and adding functionality, such as your AOP.

In your above example you're calling directly on the class, whereas if that class instance is injected into another as a Spring bean, it's injected as its proxy, and hence method calls will be invoked on the proxy (and the aspects will be triggered)

If you want to achieve the above, you could split method1/method2 into separate beans, or use a non-spring-orientated AOP framework.

The Spring doc details this, and a couple of workarounds (including my first suggestion above)

查看更多
登录 后发表回答