Yan*_*eve 5 java eclipse aspectj jar
我是aspectj的新手......
我编写了以下方面,旨在将记录添加到类型的函数调用public * doSomething*(..).如果我的主类是同一个项目的一部分,则执行方面编织时不会出现故障并执行代码.如果我将编织的代码打包到jar中并从另一个eclipse项目调用它 - 则不会执行建议.另一种情况是将方面(.aj)仅打包到一个单独的jar中并将该jar添加到eclipse中的"Aspect Path",这使得eclipse能够正确地编织方面.事情是我需要把它包装成一个jar并从其他地方调用代码.这也不起作用(毫不奇怪,我猜...)为什么?
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.CodeSignature;
import org.apache.log4j.Logger;
public aspect Logging {
pointcut allPublic(): !cflow(call(public void main(..))) && (call(public * doSomething*(..)));
private static final Logger log = Logger.getLogger("Logging.aspect");
@SuppressWarnings({"unchecked", "unused"})
private void printParameters(JoinPoint jp) {
CodeSignature methodSignature = (CodeSignature) jp.getSignature();
String methodName = methodSignature.getName();
Object[] paramNames = methodSignature.getParameterNames();
Class[] paramTypes = (Class[])methodSignature.getParameterTypes();
Object[] paramObjects = jp.getArgs();
StringBuffer infoMsg = new StringBuffer();
infoMsg.append("Entering function: " + methodName);
if (paramNames != null && paramNames.length > 0){
if (paramNames.length == 1){
infoMsg.append(" with input parameter: ["+ paramNames[1]+ "] = [" + paramObjects[1] + "]");
}
else {
infoMsg.append(" with input parameters: ");
}
for (int i = 1; i < paramNames.length; i++) {
infoMsg.append(" [" + paramTypes[i].getName() + " " + paramNames[i]+ "] = [" + paramObjects[i] + "]");
}
}
else {
infoMsg.append(" NONE");
}
log.info(infoMsg.toString());
}
@SuppressWarnings("unused")
private void printExit(JoinPoint jp) {
log.info("Exit function: " + jp.getSignature().toString());
}
before() : allPublic() {
printParameters (thisJoinPoint);
}
after() : allPublic() {
printExit(thisJoinPoint);
}
}
Run Code Online (Sandbox Code Playgroud)
应该被告知的班级:
public class Main {
private static final Logger log = Logger.getLogger("A.class");
public static void doSomethingAa(int number, String message, Map<String, String> map){
log.debug("A");
}
public static void doSomethingB(int id, String name){
log.debug("B");
}
public static void main(String[] args){
Map<String, String> map1 = new TreeMap<String, String>();
Map<String, String> map2 = new TreeMap<String, String>();
map1.put("FirstKey", "FirstValue");
map1.put("SecondKey", "SecondValue");
map2.put("Tal", "Guy");
map2.put("Happy", "Birthday");
A.doSomethingAa(17, "Tal", map1);
A.doSomethingAa(35, "Guy", map2);
A.doSomethingB(12, "TalG");
A.doSomethingB(40, "GuyG");
System.out.println("Finished running main");
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢大家!
我没有尝试在插件开发中使用aspectj,因此可能会有一些额外的东西.但是,您需要做的一些事情是确保目标在编译时正确编织并且可以运行.
更新,我一直无法重现您的问题(即它在我的盒子上工作正常).为了复制这种情况,我使用源目录中的单个Logging.aj文件创建了一个AspectJ项目.我将它作为jar文件(称为logging.jar)导出到另一个项目的根目录(另一个项目也设置为包含"Main"类的AspectJ项目).然后我修改了"main"项目的Aspect Path以包含logging.jar,并且方面和建议被编织到每个doSomethingAa()和doSomethingB()方法调用中.
我在代码中发现的唯一问题是你的静态方法调用是"A"而不是"Main".
这是主项目的.classpath文件中的条目:
<classpathentry kind="lib" path="logging.jar">
<attributes>
<attribute name="org.eclipse.ajdt.aspectpath"
value="org.eclipse.ajdt.aspectpath"/>
</attributes>
</classpathentry>
Run Code Online (Sandbox Code Playgroud)
我尝试了各种排列,我唯一能让它无法工作的方法是删除AspectJ特性或从构建路径中删除jar.
您是否还有其他可能影响工作空间的因素?
关于您在类似项目中发现的日志记录方面的另一点; 在建议之前和之后分开将导致为每个方法调用创建两次JoinPoint实例,如果您的日志记录类型编织了很多方法,这可能会导致垃圾回收问题.相反,您可以考虑使用around建议来记录入口和出口,如果您稍后决定,这也可以更容易地添加任何方法执行时间记录.
更新:根据您的评论,我向我的工作区添加了第三个项目(aj_client)并执行了以下步骤:
Client.java包含一个方法:
public static void main(String[] args) {
Main.main(args);
}
Run Code Online (Sandbox Code Playgroud)
运行时,会因NoClassDefFoundError而失败:
Exception in thread "main" java.lang.NoClassDefFoundError: org/aspectj/lang/Signature
at Client.main(Client.java:6)
Caused by: java.lang.ClassNotFoundException: org.aspectj.lang.Signature
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我修改了aj_client的.classpath,使其上有aspectjrt(通过手动将AspectJ Runtime Library类路径容器添加到.classpath)并重新启动,程序执行并输出日志语句:
Entering function: doSomethingAa with input parameters: [java.lang.String message] = [Tal] [java.util.Map map] = [{FirstKey=FirstValue, SecondKey=SecondValue}]
log4j:WARN No appenders could be found for logger (A.class).
log4j:WARN Please initialize the log4j system properly.
Exit function: void target.Main.doSomethingAa(int, String, Map)
Entering function: doSomethingAa with input parameters: [java.lang.String message] = [Guy] [java.util.Map map] = [{Happy=Birthday, Tal=Guy}]
Exit function: void target.Main.doSomethingAa(int, String, Map)
Entering function: doSomethingB with input parameters: [java.lang.String name] = [TalG]
Exit function: void target.Main.doSomethingB(int, String)
Entering function: doSomethingB with input parameters: [java.lang.String name] = [GuyG]
Exit function: void target.Main.doSomethingB(int, String)
Finished running main
Run Code Online (Sandbox Code Playgroud)
aj_client的.classpath文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.ajdt.core.ASPECTJRT_CONTAINER"/>
<!-- the other jars for the logging and target projects -->
<classpathentry kind="lib" path="/aj_target/target.jar"/>
<classpathentry kind="lib" path="/aj_target/log4j-1.2.14.jar"/>
<classpathentry kind="lib" path="/aj_target/logging.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
Run Code Online (Sandbox Code Playgroud)
我也尝试在我的Maven存储库和Eclipse插件中指向我的aspectjrt,结果相同(输出日志消息),即替换:
<classpathentry kind="con" path="org.eclipse.ajdt.core.ASPECTJRT_CONTAINER"/>
Run Code Online (Sandbox Code Playgroud)
同
<!--aspectjrt from Maven repository-->
<classpathentry kind="lib" path="C:/maven-2.2.0/repo/aspectj/aspectjrt/1.5.3/aspectjrt-1.5.3.jar"/>
Run Code Online (Sandbox Code Playgroud)
要么
<!--aspectjrt from Eclipse plugin -->
<classpathentry kind="lib" path="C:/eclipse-3.5/eclipse/plugins/org.aspectj.runtime_1.6.5.20090618034232/aspectjrt.jar"/>
Run Code Online (Sandbox Code Playgroud)
在证明编写了日志代码之后,我回过头来改变Logging.aj再次使用getLog().info()调用,并发现不再输出日志记录语句.为了解决这个问题,我添加了一个log4j.xml配置文件(只是指定了根appender)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
</layout>
</appender>
<root>
<priority value ="debug" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
Run Code Online (Sandbox Code Playgroud)
这导致以下输出:
DEBUG class - A
INFO Logging - Exit function: void target.Main.doSomethingAa(int, String, Map)
INFO Logging - Entering function: doSomethingB with input parameters: [java.lang.String name] = [TalG]
DEBUG class - B
INFO Logging - Exit function: void target.Main.doSomethingB(int, String)
INFO Logging - Entering function: doSomethingB with input parameters: [java.lang.String name] = [GuyG]
DEBUG class - B
INFO Logging - Exit function: void target.Main.doSomethingB(int, String)
Finished running main
Run Code Online (Sandbox Code Playgroud)
注意在清理,构建和导出target.jar之前,需要注意确保已清理,构建和导出logging.jar,然后清理客户端项目.如果你把订单搞砸了,你会得到不匹配的内容.
摘要
所以只要您的客户端项目引用了使用AspectJ构建的"target.jar"(因此Logging.aj被编织),并且您的类路径上有一个aspectjrt.jar 并且您已正确配置log4j,就会显示日志记录将会出现输出.
您可以通过添加类路径容器或指定兼容的aspectjrt.jar的路径来指定aspectjrt依赖项.
| 归档时间: |
|
| 查看次数: |
2231 次 |
| 最近记录: |