Spring MVC 和 AOP:@Controllers 的 @Pointcuts 仅适用于测试,不适用于生产

2024-01-06

我正在 Web 环境中使用 Spring Framework 4.3.3:

我有两个背景:

  • RootApplicationContext
  • ServletApplicationContext

我知道ServletApplicationContext包含关于Web端的所有bean,例如@Controller。此外ServletApplicationContext能够访问所有上下文或beanRootApplicationContext例如@Service, @Repository等等,直到这里我都很好。

Note它适用于@Configuration类也。 (基础设施)

因此,根据前面的介绍,我们可以这样思考:

  • ServletApplicationContext --> RootApplicationContext

需要考虑的重要一点是,逆矩阵是not可能的。

所以

  • RootApplicationContext --> ServletApplicationContext

is not可能的。它有道理而且还可以。服务器端不应该访问Web端

关于 AspectJ。我有以下内容:

@Configuration
@EnableAspectJAutoProxy
public class AopConfig {

}

这里有一个重要的一点:

  • This AopConfig is scanned by RootApplicationContext
    • 我相信ServletApplicationContext可以参考一下@Configuration通过访问RootApplicationContext

好的,当我运行我的@Test方法。

当我从服务器端执行测试类时,我使用

  • @ContextConfiguration(classes={RootApplicationContext.class} )
    • Only RootApplicationContext

而且 AOP 工作得很好。我可以通过确认AOP + logging过程如下:

  • @Service -> @Repository

当我从 Web 端执行测试类时,我使用:

  • @ContextConfiguration(classes={RootApplicationContext.class, ServletApplicationContext.class})
    • RootApplicationContext and ServletApplicationContext

而且 AOP 工作得很好。我可以通过确认AOP + logging过程如下:

  • @Controller -> @Service -> @Repository

现在对于生产我有:

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[]{RootApplicationContext.class};
    }

   @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[]{ServletApplicationContext.class};
    }

但是当我将项目导出为.war文件并通过 URL/URI aController执行了预期的行为或流程工作正常。但是关于AOP通过AOP + logging发生以下过​​程:

  • @Service -> @Repository

@Controller不会出现在输出中。预期的流程应该是:

  • @Controller -> @Service -> @Repository

那么为什么在测试中有效而不在生产中有效呢?

我已经做了研究,发现了这两个帖子:

  • Spring AOP 关于带注释控制器的建议 https://stackoverflow.com/questions/3310115/spring-aop-advice-on-annotated-controllers
  • AspectJ 不适用于 Spring @Controller 方法 https://stackoverflow.com/questions/27290247/aspectj-does-not-work-on-spring-controller-methods

实际上他们说@Configuration与 一起上课@EnableAspectJAutoProxy应该扫描通过ServletApplicationContext并且不通过RootApplicationContext

即使这是真的(根据新的实验),请考虑服务器端应该在没有 Web 环境的情况下进行测试。

对于他人@Bean关于基础设施@Configuration该关系已经解释过ServletApplicationContext --> RootApplicationContext工作效果与预期一致。正好用AOP就有这种情况。

问题01: 那么为什么会有这种行为呢?

问题02: 怎么保留AopConfig扫描者RootApplicationContext并获得预期的生产行为?

Note if AopConfig被扫描者ServletApplicationContext。以下有关测试的内容是有效的和强制性的对于服务器端@ContextConfiguration(classes={RootApplicationContext.class, AopConfig.class} )。请参阅添加AopConfig.class但我觉得AopConfig应通过扫描RootApplicationContext.


答案是@ContextConfiguration(classes={RootApplicationContext.class, ServletApplicationContext.class})测试环境中的上下文继承和生产中的上下文继承不是一回事。 在测试环境中你包括RootApplicationContext and ServletApplicationContext作为测试应用程序上下文的一部分。正如您在问题中所描述的,在生产中使用继承而不是简单的包含。

看来BeanFactoryPostProcessor(这是@EnableAspectJAutoProxy在你的情况下)来自父上下文不适用于子上下文。要使其在生产中工作,您必须显式定义@EnableAspectJAutoProxy在儿童环境中也是如此。

在这种情况下,Spring 上下文定义应如下代码所示:

@Configuration
@Import(AopConfig.class)
public class RootApplicationContext {
    ...
}

@Configuration
@Import(AopConfig.class)
public class ServletApplicationContext {
    ...
}

Or

@Configuration
@ComponentScan(basePackageClasses={AopConfig.Class, ...})
public class RootApplicationContext {
    ...
}

@Configuration
@ComponentScan(basePackageClasses={AopConfig.Class, ...})
public class ServletApplicationContext {
    ...
}

相关任务 http://jira.spring.io/browse/SPR-14753

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring MVC 和 AOP:@Controllers 的 @Pointcuts 仅适用于测试,不适用于生产 的相关文章

随机推荐