Spring AOP不能在另一个方法内调用方法

Ana*_*and 49 java spring spring-aop

ABC.java中定义了两种方法

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


public void method2(){
  ...............
  ...............  
}
Run Code Online (Sandbox Code Playgroud)

我想有AOP上的呼叫方法2.所以,我创建了一个类,AOPLogger.java,具有在方法提供方面功能的checkAccess
在配置文件中,我不喜欢的东西下面

<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>
Run Code Online (Sandbox Code Playgroud)

但是当调用我的method2时,不会调用AOP功能,即不会调用checkAccess方法的AOPLogger类.

我错过了什么?

Bri*_*new 67

该方面应用于围绕bean 的代理.请注意,每次获得对bean的引用时,它实际上不是您的配置中引用的类,而是实现相关接口的合成类,委托给实际的类并添加功能,例如您的AOP.

在上面的示例中,您直接在类上调用,而如果该类实例作为Spring bean注入另一个类,则将其作为代理注入,因此将在代理上调用方法调用(并且将触发方面)

如果要实现上述目标,可以拆分method1/ method2分成单独的bean,或使用非弹簧导向的AOP框架.

春天文档细节这一点,和几个解决方法(包括我上面的第一个建议)


Kon*_*bin 34

它可以通过自我注射使用来完成.您可以通过注入实例调用内部方法:

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

    public void method1(){
        ..
        foo.method2();
        ..
    }
    public void method2(){
        ..
    }
}
Run Code Online (Sandbox Code Playgroud)

从Spring 4.3开始,你也可以使用@Autowired来完成它.

从4.3开始,@ Autowired还会考虑自引用注入,即引用返回当前注入的bean.


小智 5

Spring AOP 框架是基于“代理”的,Understanding AOP Proxies 中的文档很好地解释了它。

当 Spring 构造一个配置了方面的 bean(如您的示例中的“ABC”)时,它实际上创建了一个充当真正 bean 的“代理”对象。代理只是将调用委托给“真实”对象,但通过创建这种间接方式,代理有机会实现“建议”。例如,您的建议可以为每个方法调用记录一条消息。在这个方案中,如果真实对象中的方法(“method1”)调用同一对象中的其他方法(例如,method2),这些调用发生在图片中没有代理,因此它没有机会实现任何建议。

在您的示例中,当调用 method1() 时,代理将有机会执行它应该执行的操作,但是如果 method1() 调用 method2(),则图片中没有任何方面。但是,如果从其他 bean 调用 method2,代理将能够执行通知。


pav*_*van 5

我有同样的问题,我通过实现Spring来实现ApplicationContextAware,BeanNameAware并实现如下相应的方法.

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;
}
Run Code Online (Sandbox Code Playgroud)

然后我在调用同一类的方法时替换this.((ABC) applicationContext.getBean(beanName))..这可确保仅通过代理调用同一类的方法.

所以method1()改变了

 public void method1(){
    .........
    ((ABC) applicationContext.getBean(beanName)).method2();
    ...........
  }
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • 虽然这种方法确实有效,但缺点是你的类现在与spring框架紧密耦合.如果您使用纯xml配置而不是注释,那么您的类可以独立于Spring.通常最好的做法是将逻辑重构为两个单独的bean.但是,如果不考虑与弹簧耦合,那么这个解决方案可能就足够了. (6认同)

归档时间:

查看次数:

41571 次

最近记录:

6 年,2 月 前