我使用 AspectJ 设置了 LTW,并且 spring 非常快速且成功。这是设置: beans.xml:
<context:annotation-config />
<aop:aspectj-autoproxy />
<context:spring-configured />
<context:load-time-weaver />
<context:component-scan base-package="com.test.service" />
我的服务将自动连接到一个类:
@Service
public class MyService {
}
父类:
public class Bar {
}
可配置类, Autowiring 服务并扩展 Bar。
@Configurable
public class BarExtended extends Bar{
@Autowired
private MyService service;
public MyService getWeavedInObject(){
return service;
}
}
并且只是一个引用父类 Bar 的类:
public class Foo {
private Bar bar;
public void setBar(Bar bar) {
this.bar = bar;
}
}
以及一个成功的测试用例。它只是创建一个 BarExtended 实例并检查 LTW 是否有效。 Foo 类不执行任何操作。
@Test
public void simple(){
Foo foo = new Foo();
BarExtended barExtended = new BarExtended();
assertNotNull("LTW didn't work.", barExtended.getWeavedInObject());
}
此测试运行绿色。但以下测试失败:
@Test
public void simple(){
Foo foo = new Foo();
BarExtended barExtended = new BarExtended();
foo.setBar(barExtended);
assertNotNull("LTW didn't work.", barExtended.getWeavedInObject());
}
我只是插入 BarExtended 类设置为 Foo 的行。沮丧使 AspjectJ 无法工作。
顺便说一句,当我更改 Foo 类以使用 BarExtended 类时(因此不需要向上转换):
public class Foo {
private BarExtended bar;
public void setBar(BarExtended bar) {
this.bar = bar;
}
}
上面的测试是有效的。有谁知道为什么当可配置对象向上转型时 AspjectJ 的行为如此奇怪?
编辑:以下也失败:
@Test
public void simple() {
Foo foo = new Foo();
BarExtended barExtended = new BarExtended();
Bar bar = (Bar) new BarExtended();
foo.setBar(bar);
assertNotNull("LTW didn't work.", barExtended.getWeavedInObject());
}
另一个 BarExtended 对象被设置为 Foo,并且第一个 barExtended 对象被 AspectJ 忽略。 但是使用反射来实例化 BarExtended 是有效的:
@Test
public void simple() throws InstantiationException, IllegalAccessException{
Foo foo = new Foo();
Bar barExtended = (Bar) BarExtended.class.newInstance();
foo.setBar(barExtended);
assertNotNull("LTW didn't work.", ((BarExtended)barExtended).getWeavedInObject());
}
很奇怪,不是吗?
非常感谢
问候,
安德烈亚斯
最佳答案
我过去遇到过麻烦,我认为 LTW 已配置,但事实并非如此,原因我不太确定。因此,我现在在配置中 100% 明确地对您的配置文件进行以下更改,看看是否一切正常。
<context:load-time-weaver aspectj-weaving="on" />
删除<aop:aspectj-autoproxy />
从您的配置来看,您不需要它,因为 LTW 确实正在运行。
当您运行 JUnit 测试时,您是否传入 vm 参数来告诉 JUnit LTW 代理在哪里?如果没有,那么 LTW 就没有运行。
以下是文档中关于 <context:load-time-weaver />
的内容
Activates a Spring LoadTimeWeaver for this application context, available as a bean with the name "loadTimeWeaver". Any bean that implements the LoadTimeWeaverAware interface will then receive the LoadTimeWeaver reference automatically; for example, Spring's JPA bootstrap support. The default weaver is determined automatically. As of Spring 2.5: detecting Sun's GlassFish, Oracle's OC4J, Spring's VM agent and any ClassLoader supported by Spring's ReflectiveLoadTimeWeaver (for example, the TomcatInstrumentableClassLoader). The activation of AspectJ load-time weaving is specified via a simple flag (the 'aspectj-weaving' attribute), with the AspectJ class transformer registered through Spring's LoadTimeWeaver. AspectJ weaving will be activated by default if a "META-INF/aop.xml" resource is present in the classpath. This also activates the current application context for applying dependency injection to non-managed classes that are instantiated outside of the Spring bean factory (typically classes annotated with the @Configurable annotation). This will only happen if the AnnotationBeanConfigurerAspect is on the classpath (i.e. spring-aspects.jar), effectively activating "spring-configured" by default. See Javadoc for org.springframework.context.annotation.EnableLoadTimeWeaving for information on code-based alternatives to bootstrapping load-time weaving support.
总而言之,<context:load-time-weaver />
似乎实际上是定义一个 id 为 loadTimeWeaver 的 bean 并扫描类路径寻找像 aop.xml 这样的特殊文件来确定是否应该打开aspectJ。为了确保aspectJ已打开,您确实需要设置aspectj-weaving="on"
这样,如果它因某种原因无法打开方面J,它将在启动时失败,这正是您想要的。在我的网络应用程序中,我有一个在网络应用程序启动时运行的测试,以确保aspectJ正在运行,如果没有运行,它就会提示。
关于java - AspectJ 和 Spring LTW 在向上转换时不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9422200/