java 为什么 Spring AOP 不在运行时编织外部 jars?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5956490/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why Spring AOP is not weaving external jars at runtime?
提问by bluefoot
I have a java application build upon Spring 3. This project has another jar as a dependency.
我有一个基于 Spring 3 的 Java 应用程序。这个项目有另一个 jar 作为依赖项。
This dependency contains a @org.aspectj.lang.annotation.Aspect
class (lets say, com.aspectprovider.aspects.MyAspect
). There's a @Before
advice to weave a method from classes that implements the interface Foo
. Something like:
这个依赖包含一个@org.aspectj.lang.annotation.Aspect
类(比方说,com.aspectprovider.aspects.MyAspect
)。有一个@Before
建议是从实现 interface 的类中编织一个方法Foo
。就像是:
@Before("execution(* com.project.Foo.save(..))")
The Foo
interface can be inside the "project" or in another jar. It doesn't matter for this example.
该Foo
接口可以是“项目”内或另一罐子。这个例子无关紧要。
My project contains classes that implements Foo
. Those are the classes that I want it to be weaved, of course.
我的项目包含实现Foo
. 当然,这些是我希望它被编织的类。
My Spring application context configuration file (applicationContext.xml
) contains the line:
我的 Spring 应用程序上下文配置文件 ( applicationContext.xml
) 包含以下行:
<aop:aspectj-autoproxy />
I also declare the aspect as a bean, and inject some properties:
我还将方面声明为 bean,并注入一些属性:
<bean id="myAspect" class="com.aspectprovider.aspects.MyAspect"
factory-method="aspectOf" >
<property name="someproperty" value="somevalue" />
</bean>
Trough logging I can see that MyAspect
is instantiated and the properties are injected. But the method save is not intercepted. This is the problem.
通过日志记录,我可以看到MyAspect
已实例化并注入了属性。但是save方法没有被拦截。这就是问题。
If I copy the aspect classes from the jar to the application that has Spring, it works. When those aspects are contained in external jars, the method save is not intercepted. Any clues?
如果我将方面类从 jar 复制到具有 Spring 的应用程序,它就可以工作。当这些方面包含在外部 jar 中时,方法 save 不会被拦截。有什么线索吗?
edit: how I am calling Foo's save method:
编辑:我如何调用 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
}
Basically, my applicationContext.xml
has the following lines:
基本上,我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>
I don't think I need to put anything like
我认为我不需要像
<context:component-scan base-package="com.project">
<context:include-filter type="aspectj" expression="com.aspectprovider.aspects.*" />
</context:component-scan>
采纳答案by bluefoot
I've ended up declaring the aspects in the spring's applicationContext xml config and removing the annotations.
我最终在 spring 的 applicationContext xml 配置中声明了方面并删除了注释。
What was working so far was using the aspectj plugin for maven, but everytime I changed a class in eclipse, I had to run $ mvn compile
(because eclipse doesn't know the aspects, and was compiling the classes without them), and that's an awful thing to say to anybody that will use MyAspect
.
到目前为止工作的是使用 maven 的 aspectj 插件,但是每次我在 eclipse 中更改一个类时,我都必须运行$ mvn compile
(因为 eclipse 不知道方面,并且在没有它们的情况下编译类),这是一件可怕的事情对任何会使用的人说MyAspect
。
Then I just created a config file and documented: to use MyAspect
, just import this config rules to your spring's context configuration.
然后我刚刚创建了一个配置文件并记录:要使用MyAspect
,只需将此配置规则导入到您的 spring 的上下文配置中。
回答by Jorge
I have the same problem. I solved this problem packaging with maven. Check the aspectj-maven-plugin
and option weaveDependency
我也有同样的问题。我用maven解决了这个问题打包。检查aspectj-maven-plugin
和选项weaveDependency
http://mojo.codehaus.org/aspectj-maven-plugin/weaveJars.html
http://mojo.codehaus.org/aspectj-maven-plugin/weaveJars.html
回答by John Vint
Considering it works perfectly fine when the classes are packaged with the application and spring I can only think it would be a classloading issue.
考虑到当类与应用程序和 spring 打包时它工作得很好,我只能认为这将是一个类加载问题。
If it works fine when your bundled in your app then then when AOP scans all the classes that it will have to monitor then it is referencing the right classloader with all the right jars. But now when you remove it and set it into a JAR it is scanning under the classloader with all of the other third party jars.
如果在您的应用程序中捆绑它时它工作正常,那么当 AOP 扫描它必须监视的所有类时,它就会使用所有正确的 jar 引用正确的类加载器。但是现在当您删除它并将其设置为 JAR 时,它会在类加载器下使用所有其他第三方 jar 进行扫描。
I am not 100% sure how it is mapped out but it could be something like this:
我不是 100% 确定它是如何绘制的,但它可能是这样的:
Bootstrap Classloader <- Third Party Classloader <- Application Class Loader (with all your classes)
\ \
aspectj.jar spring.jar
If its aspect.jar is scanning under only its classloader then it will not be able to see 'all your classes'. One way you can try confirming this is to get a heap dump of your app. Run it against Eclipse MAT, Check out Class Loader explorer and look for the aspect classes. If they do not reside under the same classloader as your application you would have to look at a way to have tomcat tell the third party libraries of the application classes.
如果它的 aspect.jar 仅在其类加载器下扫描,那么它将无法看到“所有类”。您可以尝试确认这一点的一种方法是获取应用程序的堆转储。针对 Eclipse MAT 运行它,查看类加载器资源管理器并查找方面类。如果它们与您的应用程序不在同一个类加载器下,您将不得不寻找一种方法让 tomcat 告诉应用程序类的第三方库。
回答by Karthik Ramachandran
You might try aspectJ LTW instead of Spring AOP proxy. To do this add a aop.xml to your META-INF
您可以尝试使用 aspectJ LTW 而不是 Spring AOP 代理。为此,将 aop.xml 添加到您的 META-INF
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in this package -->
<include within="org.springbyexample.aspectjLoadTimeWeaving.*" />
</weaver>
<aspects>
<!-- use only this aspect for weaving -->
<aspect name="org.springbyexample.aspectjLoadTimeWeaving.PerformanceAdvice" />
</aspects>
</aspectj>
And this is the spring portion of the config:
这是配置的弹簧部分:
See here for details : http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-aj-ltw
有关详细信息,请参见此处:http: //static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-aj-ltw
回答by Biju Kunjummen
From AspectJ in action book: aspects used with the proxy-based AOP (declared using @AspectJ or XML-based syntax) are Spring beans and shouldn't use the aspectOf() approach to instantiation.
来自AspectJ in action book:与基于代理的AOP(使用@AspectJ 或基于XML 的语法声明)一起使用的方面是Spring bean,不应使用aspectOf() 方法进行实例化。
Declare it normally and see if it works out:
正常声明它,看看它是否有效:
<bean id="myAspect" class="com.project.MyAspect">
<property name="someproperty" value="somevalue" />
</bean>
回答by avicene
take a look at ApectWerks, it does load-time weaving: http://aspectwerkz.codehaus.org/weaving.html
看看 ApectWerks,它确实加载时编织:http://aspectwerkz.codehaus.org/weaving.html