AspectJ 和 CDI
AspectJ and CDI
我正在尝试找出一种将 bean 注入方面的方法。
我是说
public class Greeter {
public String greet(String name) {....}
}
...
public aspect GreeterAspect {
@Inject
private Greeter greeter
...
}
使用 Arquillian + Wildfly 8.2.1(托管和远程)将其作为 JUnit 测试执行,我得到以下日志行:
WELD-000119: Not generating any bean definitions from x.y.z.Greeter because of underlying class loading error: Type org.aspectj.runtime.internal.AroundClosure from [Module "deployment.test.war:main" from Service Module Loader] not found.
WELD-000119: Not generating any bean definitions from x.y.z.GreeterAspect because of underlying class loading error: Type org.aspectj.lang.NoAspectBoundException from [Module "deployment.test.war:main" from Service Module Loader] not found.
我收到错误后不久
WELD-001474: Class x.y.z.Greeter is on the classpath, but was ignored because a class it references was not found: org.aspectj.runtime.internal.AroundClosure from [Module "deployment.test.war:main" from Service Module Loader].
如果我做对了,它会抱怨 aspectjrt.jar 不在类路径中,尽管我已经检查并在依赖项中得到它(使用 Maven 构建)。在 provided
范围内,尝试切换到 compile
但没有任何改变。
谁能帮我解决这个问题?
编辑:解决了最初的问题,现在是 NullPointerException
按照 simas_ch 的建议,通过将 aspectjrt.jar
添加到 Arquillian 部署来解决最初的问题。
不过,在执行时,我收到一个 NullPointerException
public class Greeter {
public String greet(String name) {....}
}
...
public aspect GreeterAspect {
@Inject
private Greeter greeter;
private pointcut pc() : execution(* x.y.z.SomeClass.someMethod(..));
String around() : pc() {
log.debug("Aspect is about to say something...");
String result = greeter.greet("Stefano");
log.debug("Aspect said: " + result);
return proceed();
}
}
我可以看到第一行日志 (Aspect is about to say something...
),然后我得到 NullPointerException
,显然 Greeter
bean 没有被注入。
我做错了什么?或者是否有可能将 bean 注入方面?
我不熟悉 CDI,但如果它没有选择方面作为依赖项注入的候选者,您应该手动设置它,最好是在方面的依赖项准备就绪后立即设置。您可以使用 AspectName.aspectOf()
.
访问一个方面(默认为单例)
也许是一个类似于这个的启动单例 bean:
@Singleton
@Startup
public class GreeterAspectSetup {
@Inject
private Greeter greeter;
@PostConstruct
private void setupGreeterAspect() {
GreeterAspect.aspectOf().setGreeter(greeter);
}
}
当然,你得把Greeter的setter加到切面,或者改变切面的字段可见性,直接设置。
感谢社区的帮助,我设法找到了解决这两个问题的方法。在这里留下足迹。
第 1 部分 - aspectjrt.jar 部署中
首先,将 Shrinkwrap
添加到我的依赖项中:
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-api-maven</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-impl-maven</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-impl-maven-archive</artifactId>
<scope>test</scope>
</dependency>
不需要 <version>
:Arquillian 的 BOM
- 已经包括在内 - 会解决这个问题。
然后将 aspectj
添加到部署类路径:
@RunWith(Arquillian.class)
public class ArquillianTest {
private static final String[] DEPENDENCIES = {
"org.aspectj:aspectjrt:1.8.7"
};
@Deployment
public static JavaArchive createEnvironement() {
JavaArchive lib = ShrinkWrap.create(JavaArchive.class, "libs.jar");
for (String dependency : DEPENDENCIES) {
lib.merge(Maven.resolver().resolve(dependency).withTransitivity().asSingle(JavaArchive.class));
}
JavaArchive jar = ShrinkWrap.create(JavaArchive.class)
// create you deployment here
.as(JavaArchive.class);
JavaArchive toBeDeployed = jar.merge(lib);
return toBeDeployed;
}
// other stuff, like tests
}
第二部分:将 bean 注入方面
经过进一步询问,我认为 simas_ch 说 CDI 不将 bean 注入方面是正确的。
提出了一个解决方法:通过方面将 @Inject
ed 成员添加到 bean 中。
public interface Advised {
String buildGreeting(String name);
}
public class AdvisedImpl implements Advised {
String buildGreeting(String name) {
return "ADVISED";
}
}
public class Greeter {
public String greet(String name) {
return "Hello, " + name + ".";
}
}
...
public aspect GreeterAspect {
@Inject
private Greeter Advised.greeter; // adding the member to the interface / class. No need for getters / setters
private pointcut pc() : execution(* x.y.z.Advised.buildGreeting(String));
String around(Advised adv, String name) : pc() && target(adv) && args(name) {
log.debug("Aspect is about to say something...");
String result = proceed(adv, name) + " - " + adv.greeter.greet(name);
log.debug("Aspect said: '" + result + "'");
return result;
}
}
鉴于测试
@Test
public void test() {
assertThat(advised, not(is(nullValue())));
assertThat(advised.buildGreeting("Stefano"), equalToIgnoringCase("advised - hello, stefano."));
}
成功了。
我正在尝试找出一种将 bean 注入方面的方法。
我是说
public class Greeter {
public String greet(String name) {....}
}
...
public aspect GreeterAspect {
@Inject
private Greeter greeter
...
}
使用 Arquillian + Wildfly 8.2.1(托管和远程)将其作为 JUnit 测试执行,我得到以下日志行:
WELD-000119: Not generating any bean definitions from x.y.z.Greeter because of underlying class loading error: Type org.aspectj.runtime.internal.AroundClosure from [Module "deployment.test.war:main" from Service Module Loader] not found.
WELD-000119: Not generating any bean definitions from x.y.z.GreeterAspect because of underlying class loading error: Type org.aspectj.lang.NoAspectBoundException from [Module "deployment.test.war:main" from Service Module Loader] not found.
我收到错误后不久
WELD-001474: Class x.y.z.Greeter is on the classpath, but was ignored because a class it references was not found: org.aspectj.runtime.internal.AroundClosure from [Module "deployment.test.war:main" from Service Module Loader].
如果我做对了,它会抱怨 aspectjrt.jar 不在类路径中,尽管我已经检查并在依赖项中得到它(使用 Maven 构建)。在 provided
范围内,尝试切换到 compile
但没有任何改变。
谁能帮我解决这个问题?
编辑:解决了最初的问题,现在是 NullPointerException
按照 simas_ch 的建议,通过将 aspectjrt.jar
添加到 Arquillian 部署来解决最初的问题。
不过,在执行时,我收到一个 NullPointerException
public class Greeter {
public String greet(String name) {....}
}
...
public aspect GreeterAspect {
@Inject
private Greeter greeter;
private pointcut pc() : execution(* x.y.z.SomeClass.someMethod(..));
String around() : pc() {
log.debug("Aspect is about to say something...");
String result = greeter.greet("Stefano");
log.debug("Aspect said: " + result);
return proceed();
}
}
我可以看到第一行日志 (Aspect is about to say something...
),然后我得到 NullPointerException
,显然 Greeter
bean 没有被注入。
我做错了什么?或者是否有可能将 bean 注入方面?
我不熟悉 CDI,但如果它没有选择方面作为依赖项注入的候选者,您应该手动设置它,最好是在方面的依赖项准备就绪后立即设置。您可以使用 AspectName.aspectOf()
.
也许是一个类似于这个的启动单例 bean:
@Singleton
@Startup
public class GreeterAspectSetup {
@Inject
private Greeter greeter;
@PostConstruct
private void setupGreeterAspect() {
GreeterAspect.aspectOf().setGreeter(greeter);
}
}
当然,你得把Greeter的setter加到切面,或者改变切面的字段可见性,直接设置。
感谢社区的帮助,我设法找到了解决这两个问题的方法。在这里留下足迹。
第 1 部分 - aspectjrt.jar 部署中
首先,将 Shrinkwrap
添加到我的依赖项中:
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-api-maven</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-impl-maven</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-impl-maven-archive</artifactId>
<scope>test</scope>
</dependency>
不需要 <version>
:Arquillian 的 BOM
- 已经包括在内 - 会解决这个问题。
然后将 aspectj
添加到部署类路径:
@RunWith(Arquillian.class)
public class ArquillianTest {
private static final String[] DEPENDENCIES = {
"org.aspectj:aspectjrt:1.8.7"
};
@Deployment
public static JavaArchive createEnvironement() {
JavaArchive lib = ShrinkWrap.create(JavaArchive.class, "libs.jar");
for (String dependency : DEPENDENCIES) {
lib.merge(Maven.resolver().resolve(dependency).withTransitivity().asSingle(JavaArchive.class));
}
JavaArchive jar = ShrinkWrap.create(JavaArchive.class)
// create you deployment here
.as(JavaArchive.class);
JavaArchive toBeDeployed = jar.merge(lib);
return toBeDeployed;
}
// other stuff, like tests
}
第二部分:将 bean 注入方面
经过进一步询问,我认为 simas_ch 说 CDI 不将 bean 注入方面是正确的。
提出了一个解决方法:通过方面将 @Inject
ed 成员添加到 bean 中。
public interface Advised {
String buildGreeting(String name);
}
public class AdvisedImpl implements Advised {
String buildGreeting(String name) {
return "ADVISED";
}
}
public class Greeter {
public String greet(String name) {
return "Hello, " + name + ".";
}
}
...
public aspect GreeterAspect {
@Inject
private Greeter Advised.greeter; // adding the member to the interface / class. No need for getters / setters
private pointcut pc() : execution(* x.y.z.Advised.buildGreeting(String));
String around(Advised adv, String name) : pc() && target(adv) && args(name) {
log.debug("Aspect is about to say something...");
String result = proceed(adv, name) + " - " + adv.greeter.greet(name);
log.debug("Aspect said: '" + result + "'");
return result;
}
}
鉴于测试
@Test
public void test() {
assertThat(advised, not(is(nullValue())));
assertThat(advised.buildGreeting("Stefano"), equalToIgnoringCase("advised - hello, stefano."));
}
成功了。