为什么Spring AOP不会在运行时编织外部jar?

blu*_*oot 7 java spring aspectj spring-aop

我有一个基于Spring 3的java应用程序构建.这个项目有另一个jar作为依赖.

这个依赖包含一个@org.aspectj.lang.annotation.Aspect类(比如说com.aspectprovider.aspects.MyAspect).有一个@Before建议从实现接口的类编织方法Foo.就像是:

@Before("execution(* com.project.Foo.save(..))")
Run Code Online (Sandbox Code Playgroud)

Foo接口可以是"项目"内或另一罐子.这个例子没关系.

我的项目包含实现的类Foo.当然,那些是我希望它被编织的类.

我的Spring应用程序上下文配置文件(applicationContext.xml)包含以下行:

<aop:aspectj-autoproxy />
Run Code Online (Sandbox Code Playgroud)

我还将方面声明为bean,并注入一些属性:

<bean id="myAspect" class="com.aspectprovider.aspects.MyAspect"
  factory-method="aspectOf" >
  <property name="someproperty" value="somevalue" />
</bean>
Run Code Online (Sandbox Code Playgroud)

通过日志记录,我可以看到MyAspect实例化并注入了属性.但是方法保存没有被截获.这就是问题.

如果我将方面类从jar复制到具有Spring的应用程序,它可以工作.当这些方面包含在外部jar中时,方法save不会被截获.有线索吗?

编辑:我如何调用Foo的保存方法:

//in a JSF managed bean
@Inject
private Foo myFoo;  //there's a implementation of Foo in a package that spring is looking at. So it is injected correctly.

public String someAction() {
    myFoo.save("something"); //the @Before advice is only called if the class containing the aspect is not in an external jar
}


//in a class with a main method
void main(String[] ars) {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    //right after the previous line, I can see in the log that MyAspect is instantiated.
    Foo myFoo = ac.getBean(Foo.class);
    myFoo.save("something"); //the @Before advice is only called if the class containing the aspect is not in an external jar
}
Run Code Online (Sandbox Code Playgroud)

基本上,我applicationContext.xml有以下几行:

<context:annotation-config />
<context:component-scan base-package="com.project" />
<context:component-scan base-package="com.aspectprovider.aspects" />
<aop:aspectj-autoproxy />
<bean id="myAspect" class="com.aspectprovider.aspects.MyAspect" factory-method="aspectOf" >
    <property name="someproperty" value="somevalue" />
</bean>
Run Code Online (Sandbox Code Playgroud)

我觉得我不需要放任何东西

<context:component-scan  base-package="com.project">
    <context:include-filter type="aspectj" expression="com.aspectprovider.aspects.*" />
</context:component-scan>
Run Code Online (Sandbox Code Playgroud)

小智 7

我也有同样的问题.我用maven解决了这个问题.检查aspectj-maven-plugin和选项weaveDependency

http://mojo.codehaus.org/aspectj-maven-plugin/weaveJars.html

  • 这就是我正在做的事情(检查[我的回复](http://stackoverflow.com/questions/5956490/why-spring-aop-is-not-weaving-external-jars-at-runtime/6238001#6238001)),但我仍然必须手动编译它或使用一些外部工具。我正在寻找加载时编织,而不是编译时编织。 (2认同)

Joh*_*int 5

考虑到当类与应用程序和 spring 打包时它工作得很好,我只能认为这将是一个类加载问题。

如果在您的应用程序中捆绑它时它工作正常,那么当 AOP 扫描它必须监视的所有类时,它就会使用所有正确的 jar 引用正确的类加载器。但是现在当您删除它并将其设置为 JAR 时,它会在类加载器下扫描所有其他第三方 jar。

我不是 100% 确定它是如何绘制的,但它可能是这样的:

Bootstrap Classloader <- Third Party Classloader  <- Application Class Loader (with all your classes)
                              \                         \
                               aspectj.jar               spring.jar
Run Code Online (Sandbox Code Playgroud)

如果它的 aspect.jar 只在它的类加载器下扫描,那么它将无法看到“所有你的类”。您可以尝试确认这一点的一种方法是获取应用程序的堆转储。针对 Eclipse MAT 运行它,查看类加载器资源管理器并查找方面类。如果它们与您的应用程序不在同一个类加载器下,您将不得不寻找一种方法让 tomcat 告诉应用程序类的第三方库。


blu*_*oot 0

我最终在 spring 的 applicationContext xml 配置中声明了各个方面并删除了注释。

到目前为止,工作是使用maven的aspectj插件,但是每次我在eclipse中更改一个类时,我都必须运行$ mvn compile(因为eclipse不知道方面,并且在没有它们的情况下编译类),这是一件可怕的事情对任何将使用MyAspect.

然后我刚刚创建了一个配置文件并记录了:要使用MyAspect,只需将此配置规则导入到 spring 的上下文配置中即可。