Spring AOP注解不起作用。

3

我有一个方面类:

@Component
@Aspect
public class LoggedRequestAspect {

    private static final Logger LOG = LoggerFactory.getLogger(LoggedRequestAspect.class);

    @Before("com.application.aspect.pointcut.LoggedRequestPointCut.LogRequest()")
    public void logRequest(){
        System.out.println("Method Executed!");
        LOG.debug("Method Executed!");
    }
}

对于注释类:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LoggedRequest {
}

最后是切入点:
public class LoggedRequestPointCut {

    @Pointcut("execution(@com.application.aspect.annotation.LoggedRequest * *(..))")
    public void LogRequest(){}

}

现在我确定,在我的控制器中已经注释了所需的API方法:

...
    @LoggedRequest
    @RequestMapping(value = "/login", method = { RequestMethod.POST })
    public @ResponseBody Map<String, Object> login(/* Param List*/){

...
    }

根据SO上其他答案的建议,我已将以下内容添加到我的spring配置中:

<context:annotation-config/>
...
<context:component-scan base-package="com.application.core"/>
...
<aop:aspectj-autoproxy />

现在所有的都不起作用了。我的 API 调用中,即 /login,所需的建议未执行。

你在哪里添加了 <aop:aspectj-autoproxy />?如果它在你的根应用程序上下文中(即 ContextLoaderListener),那么它对你的控制器将完全没有作用。此外,你还需要在 <aop:aspectj-autoproxy /> 上启用 proxy-target-class="true",才能使其对控制器起作用。 - M. Deinum
尝试将以下代码更改为:@Pointcut(@annotation(com.application.aspect.annotation.LoggedRequest))然后尝试调用您已注释的方法。 - mlewandowski
你的类路径中是否有 spring-aopaspectjweaver - Michał Kosmulski
@M.Deinum 是的,我已经把它放在了我的根应用程序上下文中。否则我该把它放在哪里? - Tariq
在由DispatcherServlet加载的上下文中,AOP仅适用于同一应用程序上下文中的bean,而不适用于父级或子级上下文中的bean。 - M. Deinum
明白了!@M.Deinum 请将其发布为答案。如果可能的话,请详细说明问题及您的解决方案为何解决了我的问题。 - Tariq
3个回答

3
在Spring中使用AOP时,只应用于同一应用程序上下文中的bean。
在典型的Web应用程序中,您将拥有一个ContextLoaderListener和一个DispatcherServlet,两者都创建一个ApplicationContext。ContextLoaderListener创建所谓的根应用程序上下文,而DispatcherServlet创建一个与根上下文相关的子上下文。
来自根的AOP配置不会影响子上下文中的bean,而子上下文中的AOP配置也不会影响根上下文中的bean。
现在,您已经配置了方面和在根上下文中,并希望它适用于位于子上下文中的bean。显然这是行不通的。将该配置移动(或复制)到子上下文中。
另一件事是,由于没有接口,您需要基于类的代理,因此您可能还想将proxy-target-class =“true”添加到元素中。

如果我使用注解配置了我的上下文,这对我意味着什么?我在配置类中添加了@EnableAspectJAutoProxy,并且还添加了切面bean,但它不起作用...在这种情况下,如何控制自动代理在哪个上下文中创建? - Jardo
放在哪里都无所谓。如果配置在根上下文中加载,而要代理的bean在子(或父)上下文中,它将不起作用。无论你使用 XML、Java 或属性文件(或任何方式)构建 ApplicationContext, 这都没有关系。 - M. Deinum
好的,但是我如何确保AOP配置和要代理的bean在同一个上下文中? - Jardo
一个人怎样把AOP配置移动到不同的上下文中?只需将配置文件复制到包含连接点的类的相同包中,这样简单吗? - rj2700

0

看起来一切都没问题,但你应该写成这样:

<aop:aspectj-autoproxy >
        <aop:include name="loggedRequestAspect"/>
    </aop:aspectj-autoproxy>

因为使用这个最终配置,你可以告诉Spring自动代理基础设施在自动代理过程中考虑哪些bean。 关键点在于,如果你想使用切面记录方法调用,那么很好,但是如果你想使用切面记录HTTP调用,它将无法工作,在这种情况下,使用拦截器可能是一个不错的选择。

你可以使用你的org.springframework.web.servlet.HandlerInterceptor或org.springframework.web.context.request.WebRequestInterceptor实现

然后像这样在org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter中注册:

@Configuration
class MyWebConfiguratio extends WebMvcConfigurerAdapter {
....
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new HandlerInterceptor() {
               ...
            }).addPathPatterns("....");
            registry.addInterceptor(new WebMvcConfigurerAdapter() {
              ....
            }).addPathPatterns("....");
        }

      ....
}

在Java配置中或者

 <mvc:interceptors>
        <bean id="localeChangeInterceptor"
              class="com.yourapp.Interceptor""/>
    </mvc:interceptors>

在你的 XML 配置文件中使用 MVC 命名空间。
希望这能帮到你。

我在工作中使用了这种配置,对我来说运行良好。 - Valerio Vaudi

0
在我的情况下,@Cacheable 禁用了我的 AOP 注解断点。只需将 @Cacheable 放在我的 AOP 注解后面即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接