【问题标题】:Spring AOP not working, when the method is called internally within a bean当在 bean 内部调用该方法时,Spring AOP 不起作用
【发布时间】:2015-06-02 13:54:25
【问题描述】:

我的应用程序中有几个方面编码。除以下内容外,其他所有内容均有效。

服务接口

package com.enbiso.proj.estudo.system.service;
...
public interface MessageService {
     ...
     Message reply(Message message);
     Message send(Message message);
     ...
}

服务实施

package com.enbiso.proj.estudo.system.service.impl;
....
@Service("messageService")
public class MessageServiceImpl implements MessageService {
   ...
   @Override
   public Message reply(Message message) {
        ...
        return this.send(message);
   }

   @Override
   public Message send(Message message) {
         ...
   }
}

方面

@Aspect
@Component
public class NewMessageAspect {
    ...
    @AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(..))", 
                    returning = "message")
    public void perform(Message message){
       ...
    }
}

当我尝试执行send 方法时,调试点在perform 方面没有受到影响。

更新

我做了一些调查,发现这不起作用,当从reply方法调用send方法时,如下所示

@Autowire MessageService messageService;
...
messageService.reply(message);

但是如果我调用方法messageService.send(message) 它工作正常。但是由于reply方法在内部调用了send方法,不应该也调用aspect吗?

我不知道我做错了什么。请帮帮我。

【问题讨论】:

    标签: java spring spring-boot spring-aop


    【解决方案1】:

    感谢 jst 解决问题。仅出于 SO 中未来开发人员的信息目的,我发布了此问题的完整答案


    让我们假设有一个来自 SimplePojo 的 bean
    public class SimplePojo implements Pojo {
        public void foo() {
            this.bar();
        }
        public void bar() {
            ...
        }
    }
    

    当我们调用foo() 方法时,它会重新调用其中的bar() 方法。即使方法foo() 是从AOP 代理调用的,但bar() 的内部调用并没有被AOP 代理覆盖。

    因此,如果有任何附加到方法 bar() 的建议,最终会导致不被调用

    解决方案

    使用AopContext.currentProxy() 调用该方法。不幸的是,这将逻辑与 AOP 结合在一起。

    public void foo() {
       ((Pojo) AopContext.currentProxy()).bar();
    }
    

    参考:

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies

    【讨论】:

    • 我喜欢a similar SO post 的另一个解决方案是将这两种方法分成不同的bean。所以 send 将在 SendMessageService bean 中,而 reply 将在 ReplyMessageService bean 中。这将避免将 aop 与业务逻辑耦合。
    【解决方案2】:

    您在自调用方面遇到了 Spring AOP 的限制。您基本上可以通过使用 AopContext.currentProxy()、将代码重构为不同的 bean 或使用完整的 ApsectJ 编织来解决它。

    请参阅此处的说明和解决方法。 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies

    【讨论】:

    • 非常感谢。这让我们对背后发生的事情有了一些了解。 :)
    【解决方案3】:

    我猜问题是@args 条件。

    Spring 文档声明如下:

    @args - limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given type(s) 
    

    因此@args 的参数必须是类型表达式。所以正确的切入点表达式是

    @AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(..)) && args(com.enbiso.proj.estudo.system.service.impl.Message")
    

    或者干脆

    @AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(com.enbiso.proj.estudo.system.service.impl.Message))")
    

    Message的包如果不合适请调整。

    【讨论】:

    猜你喜欢
    • 2015-06-06
    • 2021-07-03
    • 1970-01-01
    • 2016-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-27
    相关资源
    最近更新 更多