AspectJ 的 NoSuchMethodError
NoSuchMethodError with AspectJ
注意:这是概念实施的证明,而不是最终结果。
我有第三名。聚会附加组件,我想限制他们对声音的使用,例如限制持续时间等(安全管理器不可能)。为了实现这一点,我考虑用包装器替换 AudioSystem.getLine() 的 return。
这是测试方面:
@Aspect
public class MixerAspect {
@Around("execution(* javax.sound.sampled.AudioSystem.getLine(javax.sound.sampled.Line.Info))")
public Object getLineAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("AspectJ");
pjp.getArgs();
Line ret = (Line) pjp.proceed();
return ret;
}
}
每个附加组件都有自己的 class 加载器,它们通常不共享对象,所以这就是我想出的:
@Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
....
if (className.equals(AudioSystem.class.getName())) {
.....
byte[] array = buffer.toByteArray();
try {
if (mixed == null)
mixed = weaver.defineClass(className, array, new CodeSource(mixerAspect, (CodeSigner[]) null));
return mixed;
} catch (IOException e) {
throw new ClassNotFoundException("unable to define class", e);
}
这是 WeavingURLClassloader 的初始化代码:
weaver = new WeavingURLClassLoaderHelper(new URL[0], parent);
weaver.addURL(aspects[0]);
parent 是 class 加载器,可以访问 Mixer 切面,切面是一个 url 数组,其中唯一的元素是一个指向 MixerAspect 所在目录的元素。
我的 aop.xml:
<aspectj>
<aspects>
<aspect name="org.intellimate.izou.security.replaced.MixerAspect"/>
</aspects>
<weaver options="-Xset:weaveJavaxPackages=true -verbose -showWeaveInfo -debug">
<!-- Weave types that are within the javax.* or org.aspectj.*
packages. Also weave all types in the foo package that do
not have the @NoWeave annotation. -->
<include within="javax.*"/>
<include within="org.intellimate.izou.security.replaced.*"/>
<include within="javax.sound.sampled.AudioSystem"/>
</weaver>
</aspectj>
这是(相关)日志:
....(no relevant log)
TraceFactory.instance=org.aspectj.weaver.tools.Jdk14TraceFactory@53aad5d5
[WeavingURLClassLoaderHelper] info AspectJ Weaver Version 1.8.5 built on Thursday Jan 29, 2015 at 01:03:58 GMT
[WeavingURLClassLoaderHelper] info register classloader ro.fortsoft.pf4j.IzouPluginClassLoader$WeavingURLClassLoaderHelper
[WeavingURLClassLoaderHelper] info using configuration /Users/LeanderK/IdeaProjects/Izou/target/classes/META-INF/aop.xml
[WeavingURLClassLoaderHelper] info register aspect org.intellimate.izou.security.replaced.MixerAspect
[WeavingURLClassLoaderHelper] info AspectJ Weaver Version 1.8.5 built on Thursday Jan 29, 2015 at 01:03:58 GMT
[WeavingURLClassLoaderHelper] info register classloader ro.fortsoft.pf4j.IzouPluginClassLoader$WeavingURLClassLoaderHelper
[WeavingURLClassLoaderHelper] info using configuration /Users/LeanderK/IdeaProjects/Izou/target/classes/META-INF/aop.xml
[WeavingURLClassLoaderHelper] info register aspect org.intellimate.izou.security.replaced.MixerAspect
...(no relevant log)
[WeavingURLClassLoaderHelper] debug weaving 'javax.sound.sampled.AudioSystem'
[WeavingURLClassLoaderHelper] weaveinfo Join point 'method-execution(javax.sound.sampled.Line javax.sound.sampled.AudioSystem.getLine(javax.sound.sampled.Line$Info))' in Type 'javax.sound.sampled.AudioSystem' (AudioSystem.java:410) advised by around advice from 'org.intellimate.izou.security.replaced.MixerAspect' (MixerAspect.class(from MixerAspect.java))
[WeavingURLClassLoaderHelper] debug generating class 'javax.sound.sampled.AudioSystem$AjcClosure1'
2015-05-24 20:12:13,945 FATAL [Thread-5] org.intellimate.izou.threadpool.ThreadPoolManager (ThreadPoolManager.java:59) - unable to provide callback for: org.intellimate.izou.addon.AddOnManager$$Lambda/970865974@1f4f3b69
java.util.concurrent.CompletionException: java.lang.NoSuchMethodError: org.intellimate.izou.security.replaced.MixerAspect.aspectOf()Lorg/intellimate/izou/security/replaced/MixerAspect;
at java.util.concurrent.CompletableFuture.internalComplete(CompletableFuture.java:205) [?:1.8.0_25]
at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:459) [?:1.8.0_25]
at java.util.concurrent.CompletableFuture$Async.run(CompletableFuture.java:428) [?:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_25]
at org.intellimate.izou.threadpool.ThreadPoolManager$LoggingThreadFactory.run(ThreadPoolManager.java:73) [classes/:?]
Caused by: java.lang.NoSuchMethodError: org.intellimate.izou.security.replaced.MixerAspect.aspectOf()Lorg/intellimate/izou/security/replaced/MixerAspect;
at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:410) ~[?:1.8.0_25]
at leanderk.izou.playground.ExampleAddOn.prepare(ExampleAddOn.java:41) ~[?:?]
at org.intellimate.izou.sdk.addon.AddOn.register(AddOn.java:41) ~[?:?]
at org.intellimate.izou.addon.AddOnManager$$Lambda/970865974.run(Unknown Source) ~[?:?]
at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:454) ~[?:1.8.0_25]
... 4 more
貌似不织布,为什么呢?我不知道还能尝试什么。我有以下依赖项:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
</dependency>
更复杂的是,class 加载程序位于另一个项目中,该项目具有对该项目的简单 Maven 依赖性。
我缺少一些 aspectj 初始化吗?
编辑以澄清答案:
您还必须通过 WeavingURLClassloader 定义方面,这是我的(示例 - 它的简化)代码,同样可以应用于您想要混合的每个 class。在我的例子中,class 已经通过 system-classloader 加载,所以我不得不明确地调用 define(小心,相同的 classes 从不同的 class 加载装载机不一样!)
private Class mixer = null;
......
@Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
.....
else if (className.contains("MixerAspect")) {
InputStream is = this.getResourceAsStream(className.replace('.', '/') + ".class");
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
try {
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
} catch (IOException e) {
throw new ClassNotFoundException("unable to load class", e);
}
try {
buffer.flush();
} catch (IOException e) {
throw new ClassNotFoundException("unable to load class", e);
}
byte[] array = buffer.toByteArray();
URL mixerAspect = getResource("org/intellimate/izou/security/replaced/MixerAspect.class");
try {
if (mixer == null) {
mixer = weaver.defineClass(className, array, new CodeSource(mixerAspect, (Certificate[]) null));
}
return mixer;
} catch (IOException e) {
throw new ClassNotFoundException("unable to define class", e);
}
}
如果使用注释样式方面并使用 javac 进行编译,您需要在加载时将方面 'finished off' 传递给编织器本身。如果你不这样做,那么它就不能生成像 aspectOf()
这样的辅助方法,这些辅助方法将从其他尝试使用该方面的编织类型调用。 aspectOf()
的 NoSuchMethodError
告诉我这个方面没有编织。 aspectOf()
被调用的事实告诉我其他类型正在成功编织。几个选择:
使用ajc编译你的MixerAspect,这会在编译时添加额外的方法
确保您的编织过程允许编织 MixerAspect。确保它加载了另一个正在编织的 类 而不是父加载器?还是让parent loader也做编织?
是的,我选择了第二个,它在 LTW 中有效。
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!--<weaver options="-verbose -showWeaveInfo -debug">-->
<include within="com.rabbitmq.client.impl.ChannelN"/>
<include within="**.MQAspect"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="**.MQAspect"/>
</aspects>
</aspectj>
注意:这是概念实施的证明,而不是最终结果。
我有第三名。聚会附加组件,我想限制他们对声音的使用,例如限制持续时间等(安全管理器不可能)。为了实现这一点,我考虑用包装器替换 AudioSystem.getLine() 的 return。 这是测试方面:
@Aspect
public class MixerAspect {
@Around("execution(* javax.sound.sampled.AudioSystem.getLine(javax.sound.sampled.Line.Info))")
public Object getLineAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("AspectJ");
pjp.getArgs();
Line ret = (Line) pjp.proceed();
return ret;
}
}
每个附加组件都有自己的 class 加载器,它们通常不共享对象,所以这就是我想出的:
@Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
....
if (className.equals(AudioSystem.class.getName())) {
.....
byte[] array = buffer.toByteArray();
try {
if (mixed == null)
mixed = weaver.defineClass(className, array, new CodeSource(mixerAspect, (CodeSigner[]) null));
return mixed;
} catch (IOException e) {
throw new ClassNotFoundException("unable to define class", e);
}
这是 WeavingURLClassloader 的初始化代码:
weaver = new WeavingURLClassLoaderHelper(new URL[0], parent);
weaver.addURL(aspects[0]);
parent 是 class 加载器,可以访问 Mixer 切面,切面是一个 url 数组,其中唯一的元素是一个指向 MixerAspect 所在目录的元素。 我的 aop.xml:
<aspectj>
<aspects>
<aspect name="org.intellimate.izou.security.replaced.MixerAspect"/>
</aspects>
<weaver options="-Xset:weaveJavaxPackages=true -verbose -showWeaveInfo -debug">
<!-- Weave types that are within the javax.* or org.aspectj.*
packages. Also weave all types in the foo package that do
not have the @NoWeave annotation. -->
<include within="javax.*"/>
<include within="org.intellimate.izou.security.replaced.*"/>
<include within="javax.sound.sampled.AudioSystem"/>
</weaver>
</aspectj>
这是(相关)日志:
....(no relevant log)
TraceFactory.instance=org.aspectj.weaver.tools.Jdk14TraceFactory@53aad5d5
[WeavingURLClassLoaderHelper] info AspectJ Weaver Version 1.8.5 built on Thursday Jan 29, 2015 at 01:03:58 GMT
[WeavingURLClassLoaderHelper] info register classloader ro.fortsoft.pf4j.IzouPluginClassLoader$WeavingURLClassLoaderHelper
[WeavingURLClassLoaderHelper] info using configuration /Users/LeanderK/IdeaProjects/Izou/target/classes/META-INF/aop.xml
[WeavingURLClassLoaderHelper] info register aspect org.intellimate.izou.security.replaced.MixerAspect
[WeavingURLClassLoaderHelper] info AspectJ Weaver Version 1.8.5 built on Thursday Jan 29, 2015 at 01:03:58 GMT
[WeavingURLClassLoaderHelper] info register classloader ro.fortsoft.pf4j.IzouPluginClassLoader$WeavingURLClassLoaderHelper
[WeavingURLClassLoaderHelper] info using configuration /Users/LeanderK/IdeaProjects/Izou/target/classes/META-INF/aop.xml
[WeavingURLClassLoaderHelper] info register aspect org.intellimate.izou.security.replaced.MixerAspect
...(no relevant log)
[WeavingURLClassLoaderHelper] debug weaving 'javax.sound.sampled.AudioSystem'
[WeavingURLClassLoaderHelper] weaveinfo Join point 'method-execution(javax.sound.sampled.Line javax.sound.sampled.AudioSystem.getLine(javax.sound.sampled.Line$Info))' in Type 'javax.sound.sampled.AudioSystem' (AudioSystem.java:410) advised by around advice from 'org.intellimate.izou.security.replaced.MixerAspect' (MixerAspect.class(from MixerAspect.java))
[WeavingURLClassLoaderHelper] debug generating class 'javax.sound.sampled.AudioSystem$AjcClosure1'
2015-05-24 20:12:13,945 FATAL [Thread-5] org.intellimate.izou.threadpool.ThreadPoolManager (ThreadPoolManager.java:59) - unable to provide callback for: org.intellimate.izou.addon.AddOnManager$$Lambda/970865974@1f4f3b69
java.util.concurrent.CompletionException: java.lang.NoSuchMethodError: org.intellimate.izou.security.replaced.MixerAspect.aspectOf()Lorg/intellimate/izou/security/replaced/MixerAspect;
at java.util.concurrent.CompletableFuture.internalComplete(CompletableFuture.java:205) [?:1.8.0_25]
at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:459) [?:1.8.0_25]
at java.util.concurrent.CompletableFuture$Async.run(CompletableFuture.java:428) [?:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_25]
at org.intellimate.izou.threadpool.ThreadPoolManager$LoggingThreadFactory.run(ThreadPoolManager.java:73) [classes/:?]
Caused by: java.lang.NoSuchMethodError: org.intellimate.izou.security.replaced.MixerAspect.aspectOf()Lorg/intellimate/izou/security/replaced/MixerAspect;
at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:410) ~[?:1.8.0_25]
at leanderk.izou.playground.ExampleAddOn.prepare(ExampleAddOn.java:41) ~[?:?]
at org.intellimate.izou.sdk.addon.AddOn.register(AddOn.java:41) ~[?:?]
at org.intellimate.izou.addon.AddOnManager$$Lambda/970865974.run(Unknown Source) ~[?:?]
at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:454) ~[?:1.8.0_25]
... 4 more
貌似不织布,为什么呢?我不知道还能尝试什么。我有以下依赖项:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
</dependency>
更复杂的是,class 加载程序位于另一个项目中,该项目具有对该项目的简单 Maven 依赖性。 我缺少一些 aspectj 初始化吗?
编辑以澄清答案: 您还必须通过 WeavingURLClassloader 定义方面,这是我的(示例 - 它的简化)代码,同样可以应用于您想要混合的每个 class。在我的例子中,class 已经通过 system-classloader 加载,所以我不得不明确地调用 define(小心,相同的 classes 从不同的 class 加载装载机不一样!)
private Class mixer = null;
......
@Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
.....
else if (className.contains("MixerAspect")) {
InputStream is = this.getResourceAsStream(className.replace('.', '/') + ".class");
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
try {
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
} catch (IOException e) {
throw new ClassNotFoundException("unable to load class", e);
}
try {
buffer.flush();
} catch (IOException e) {
throw new ClassNotFoundException("unable to load class", e);
}
byte[] array = buffer.toByteArray();
URL mixerAspect = getResource("org/intellimate/izou/security/replaced/MixerAspect.class");
try {
if (mixer == null) {
mixer = weaver.defineClass(className, array, new CodeSource(mixerAspect, (Certificate[]) null));
}
return mixer;
} catch (IOException e) {
throw new ClassNotFoundException("unable to define class", e);
}
}
如果使用注释样式方面并使用 javac 进行编译,您需要在加载时将方面 'finished off' 传递给编织器本身。如果你不这样做,那么它就不能生成像 aspectOf()
这样的辅助方法,这些辅助方法将从其他尝试使用该方面的编织类型调用。 aspectOf()
的 NoSuchMethodError
告诉我这个方面没有编织。 aspectOf()
被调用的事实告诉我其他类型正在成功编织。几个选择:
使用ajc编译你的MixerAspect,这会在编译时添加额外的方法
确保您的编织过程允许编织 MixerAspect。确保它加载了另一个正在编织的 类 而不是父加载器?还是让parent loader也做编织?
是的,我选择了第二个,它在 LTW 中有效。
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!--<weaver options="-verbose -showWeaveInfo -debug">-->
<include within="com.rabbitmq.client.impl.ChannelN"/>
<include within="**.MQAspect"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="**.MQAspect"/>
</aspects>
</aspectj>