代码之家  ›  专栏  ›  技术社区  ›  Yaneeve

为什么我的方面是在其原始设置中执行的,而不是在打包为单独的jar并从其他地方调用时执行的?

  •  5
  • Yaneeve  · 技术社区  · 16 年前

    我是aspectj的新手。。。

    我编写了以下方面,旨在向类型为的函数调用添加日志记录 public * doSomething*(..)

    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);
        }
    }
    

    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");
    
        }
    
    }
    

    谢谢大家!

    1 回复  |  直到 16 年前
        1
  •  8
  •   Rich Seller    16 年前

    我还没有尝试在插件开发中使用aspectj,所以可能还有一些额外的东西。但是,为了确保目标在编译时正确编织并可以运行,您需要做一些事情。

    • 方面需要位于类路径上的导出包中
    • 目标插件需要在类路径上有aspectjrt,这样它才能处理方面
    • 编译目标时,需要使用aspectj编译器来编织目标。

    更新,我无法重现您的问题(即,它在我的盒子上工作正常)。为了复制这种情况,我在源目录中创建了一个带有单个Logging.aj文件的AspectJ项目。我将其作为jar文件(称为logging.jar)导出到另一个项目的根目录(另一个项目也设置为包含“Main”类的AspectJ项目)。然后,我修改了“main”项目的方面路径,以包括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>
    

    我尝试过各种排列,我唯一能做到的就是 工作是通过删除AspectJ特性或从构建路径中删除jar。

    您是否忽略了其他可能影响您工作空间的因素?



    更新:根据您的评论,我向我的工作区添加了第三个项目(aj_client),并完成了以下步骤:

    1. 修改Logging.aj以执行System.out调用,排除了log4j配置问题
      • 将aj_日志(包含logging.aj的AspectJ项目)导出到logging.jar
      • 将logging.jar添加到aj_目标的方面路径
      • 将aj_目标(包含Main.java的AspectJ项目)导出到target.jar
      • 在aj_客户端项目(没有AspectJ特性)中创建了一个新类(Client.java)。
      • 将target.jar、logging.jar(和log4j.jar)添加到aj_客户机的Java构建路径并运行它。

    Client.java包含一个方法:

    public static void main(String[] args) {
        Main.main(args);
    }
    

    运行时,此操作失败,并出现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
    

    为了解决这个问题,我修改了aj_客户端的.classpath,使其上有aspectjrt(通过手动添加 AspectJ运行库 类路径容器)并重新运行,程序执行并输出日志记录语句:

    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
    

    aj_客户端的.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>
    

    <classpathentry kind="con" path="org.eclipse.ajdt.core.ASPECTJRT_CONTAINER"/>
    

    具有

    <!--aspectjrt from Maven repository-->
    <classpathentry kind="lib" path="C:/maven-2.2.0/repo/aspectj/aspectjrt/1.5.3/aspectjrt-1.5.3.jar"/>
    

    <!--aspectjrt from Eclipse plugin -->
    <classpathentry kind="lib" path="C:/eclipse-3.5/eclipse/plugins/org.aspectj.runtime_1.6.5.20090618034232/aspectjrt.jar"/>
    

    在证明日志代码是编织的之后,我返回并将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>
    

    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
    

    注意:在清理、构建和导出target.jar之前,您需要小心确保已经清理、构建和导出了logging.jar,然后才清理客户机项目。如果你把订单搞砸了,你会得到不匹配的内容。


    总结

    类路径上有一个aspectjrt.jar 您已经正确配置了log4j,日志将被输出。

    您可以通过添加类路径容器或指定兼容aspectjrt.jar的路径来指定aspectjrt依赖项