【问题标题】:Spring Aspect not executed when defined in other JAR在其他 JAR 中定义时未执行 Spring Aspect
【发布时间】:2012-04-18 06:55:43
【问题描述】:

我有一个由两个子项目组成的项目,它们都是 Spring 项目,并且每个都有一个 applicationContext.xml。

一个是框架项目(最终成为 JAR),一个是实际应用程序(最终成为 WAR,依赖于 JAR 并将 JAR 的 applicationContext.xml 导入它自己的 applicationContext.xml)。

在框架项目中,我为所有公共方法定义了一个方面。

@Aspect
@Configurable
public class MyAspect {

    @Autowired
    private SomeBean mBean;

    @Pointcut("execution(public * *(..))")
    public void anyPublicMethod() {
    }

    @Before("anyPublicMethod()")
    public void checkAuthorization(JoinPoint pJoinPoint) {
        mBean.doSomething();
    }
}

并且我已经在框架的applicationContext.xml中激活了AOP(由实际应用项目的applicationContext.xml导入)。

...
    <context:spring-configured />

    <context:component-scan base-package="com.mypackage" />

    <aop:aspectj-autoproxy/>
...

在框架项目中进行测试时,方面会在调用 Spring bean 上的公共方法时按预期执行。

如上所述,框架项目作为依赖项包含在应用程序项目中,但是当在任何 Spring bean 上调用应用程序项目中的匹配方法(任何公共)时,不会执行方面。

我也尝试过使用方面的 XML 配置。这会导致相同的行为。

【问题讨论】:

    标签: spring aspectj spring-aop


    【解决方案1】:

    恕我直言,您可以稍微调整方法。

    我要做的第一件事是将战争的应用程序上下文的配置委托给 web.xml:

    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>WEB-INF/classes/spring*.xml</param-value>
    </context-param>
    

    其次,我会在你的 war 文件的应用程序上下文中启用 aop,因为这是你想要使用它的地方。听起来,目前,您使用 aop 配置导入应用程序上下文只是为了将其放入您的 Web 项目中,这可能是错误的。

    最后我假设这些是运行时而不是编译的方面,在后一种情况下,无论依赖关系如何,您都需要在您的战争项目中使用 aspectj 重新编译。

    【讨论】:

    • 在应用程序上下文中启用 AOP 并不能解决问题。
    • 我还读到 spring 自动代理仅适用于 spring 管理的 bean,而可配置的不是。请尝试将其标记为组件?参考 - 7.2.2 声明方面static.springsource.org/spring/docs/3.0.5.RELEASE/reference/…
    • 我认为您在这里混淆了方面的应用及其定义。文档说,一个方面只能应用到 Spring bean。这与方面本身的声明无关。它甚至必须只使用@Aspect(不使用@Configurable@Component)来工作。在我的示例中,切面是 @Configurable,另外因为要注入 @Autowired 字段。
    • 抱歉,小误会。我的意思是传达这部分“但是,请注意@Aspect 注释不足以在类路径中进行自动检测”。我原以为您可能需要一个与组件继承树相关的构造型。
    • 尝试了你所有的建议,但仍然没有调用方面。
    【解决方案2】:

    Spring MVC webapps 中,您实际上有2 个上下文:根上下文和servlet 上下文。请务必在 servlet 的上下文中配置您的方面。事实上,servlet 的上下文“看到”了根——而不是相反:

    在 Web MVC 框架中,每个 DispatcherServlet 都有自己的 WebApplicationContext,它继承了所有已经定义在 根 WebApplicationContext。这些继承的 bean 可以 在特定于 servlet 的范围内被覆盖,您可以定义新的 给定 Servlet 实例的本地特定范围的 bean。

    因此,如果您希望将方面应用于其 bean,则必须在 [servlet-name]-servlet.xml 文件中而不是在其他文件中导入框架配置。

    【讨论】:

      【解决方案3】:

      我就是这样做的:

      <context:annotation-config/>
      <context:component-scan base-package="my.pkg" scoped-proxy="interfaces"/> 
      <aop:aspectj-autoproxy proxy-target-class="true" />
      

      虽然我不知道它是否适用于您的情况....如果您在 github 上设置项目的精简版本会有所帮助。

      这不需要任何字节码编织或检测 jvm。只需确保在调用相关方法时使用自动注入的属性,即。

      @Autowired
      private MyType myTypeInstance; // MyType is usually an interface
      
      public void someMethod() {
          // myTypeInstance is actually a proxy object... thereby providing the
          // access point for the weaving stuff. (as far as I understand it)
          myTypeInstance.method();
      }
      

      否则,如果您不喜欢 spring 管理的 AOP 类代理,请关注 these instructions

      【讨论】:

        【解决方案4】:

        我认为你需要让你的方面成为一个组件才能让它被 spring 识别:

        http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-at-aspectj

        通过组件扫描自动检测方面

        您可以注册 方面类作为 Spring XML 配置中的常规 bean,或者 通过类路径扫描自动检测它们 - 就像任何其他 Spring 管理的 bean。但是,请注意 @Aspect 注释不是 足以在类路径中进行自动检测:为此,您 需要添加一个单独的 @Component 注释(或者 符合以下规则的自定义构造型注释 Spring 的组件扫描器)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-01-01
          • 2022-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-08
          • 2017-03-20
          相关资源
          最近更新 更多