Warum werden meine Aspekte in ihrer ursprünglichen Umgebung ausgeführt und nicht, wenn es als separates Glas verpackt und von anderswo genannt?

StackOverflow https://stackoverflow.com/questions/1265487

  •  13-09-2019
  •  | 
  •  

Frage

Ich bin ein Neuling auf aspectj ...

Ich habe den folgenden Aspekt geschrieben, die Protokollierung hinzufügen sollte, Anrufe vom Typ public * doSomething*(..) funktionieren. Wenn mein Hauptklasse Teil des gleichen Projekts das Weben des Aspektes ist, ohne Pannen durchgeführt und der Code ausgeführt wird. Wenn ich den gesponnenen Code in ein Gefäß zusammenpacken und von einem anderen Eclipse-Projekt nennen - der Rat nicht ausgeführt wird. Ein weiteres Szenario ist der Aspekt Einpacken (.aj) nur in einem separaten Gefäß und fügte hinzu, dass Glas in die „Aspect Path“ in Eclipse ermöglicht diese Eklipse den Aspekt richtig zu weben. Die Sache ist ich brauche diese in ein Gefäß einpacken und rufen Sie den Code aus anderen Ländern. Das funktioniert nicht entweder (nicht überraschend nehme ich an ...) Warum?

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

Die Klasse, die sollte beraten werden:

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

    }

}

Danke allen!

War es hilfreich?

Lösung

Ich habe nicht mit aspectj in Plugin-Entwicklung versucht, so könnte es ein paar zusätzlichen Dinge sein. Aber hier ist ein paar Dinge, die Sie tun müssen, um das Ziel zu gewährleisten gewebt sind richtig bei der Kompilierung und können ausgeführt werden.

  • Das Plugin, das Bedürfnis gewebt wird eine Abhängigkeit von dem Plugin hat den Aspekt mit
  • Der Aspekt muss in dem Exportierte Packages auf dem Classpath
  • sein
  • Das Ziel Plugin benötigt aspectjrt auf dem Classpath haben, damit er die Aspekte behandeln kann
  • Der aspectj Compiler muss verwendet werden, um das Ziel zu weben, wenn es kompiliert wird.

Update, ich habe es nicht gelungen, das Problem zu reproduzieren (das heißt es funktioniert auf meiner Box in Ordnung). Um die Situation zu replizieren Ich habe ein AspectJ Projekt mit der einzigen Logging.aj Datei im Quellverzeichnis. Ich exportiert das als JAR-Datei (genannt logging.jar) in ein anderes Projekt der Wurzel (das andere Projekt auch als AspectJ Projekt mit der „Main“ Klasse einrichten). Ich änderte dann die Richtung Pfad des „main“ Projektes die logging.jar einzubeziehen und die Aspekte und die Beratung wurde zu jedem doSomethingAa gewebt () und doSomethingB () -Methode.

Das einzige Problem, das ich mit dem Code gefunden wurde, dass Ihre statischen Methodenaufrufe für „A“ sind eher als „Main“.

Hier ist der Eintrag aus dem .classpath-Datei des Hauptprojektes:

<classpathentry kind="lib" path="logging.jar">
  <attributes>
    <attribute name="org.eclipse.ajdt.aspectpath"
        value="org.eclipse.ajdt.aspectpath"/>
  </attributes>
</classpathentry>

Ich habe verschiedene Permutationen versucht, und die einzigen Möglichkeiten, kann ich es auf erhält nicht Arbeit wird durch die AspectJ Natur zu entfernen oder das Glas aus dem Build-Pfad zu entfernen.

Gibt es andere Faktoren, die den Arbeitsbereich zu beeinflussen können, die Sie ausgelassen haben?


Ein weiterer Punkt über Ihren Logging-Aspekt, den ich in einem ähnlichen Projekt gefunden; Separate vor und nach der Beratung in JoinPoint Instanzen werden erstellt zweimal für jeden Methodenaufruf führt, kann dies ein Problem für die Garbage Collection verursachen, wenn Ihre Logging-Art eine Menge von Methoden webt. Stattdessen könnte man bedenkt, um Ratschläge sowohl mit dem Ein- und Ausstieg zu protokollieren, das es auch leichter macht in jeder Methode Ausführungszeit-Protokollierung hinzufügen, wenn Sie später entscheiden.


Update: Auf der Basis Ihrer Kommentare, fügte ich ein drittes Projekt (aj_client) zu meinem Arbeitsplatz und ging durch die folgenden Schritte:

  1. Modifizierte Logging.aj System.out nennt, Ausschluss log4j Konfigurationsprobleme zu tun
    • exportierte aj_logging (AspectJ Projekt mit Logging.aj) logging.jar
    • hinzugefügt logging.jar den Aspekt Pfad der aj_target
    • exportierte aj_target (AspectJ Projekt mit Main.java) target.jar
    • Erstellt eine neue Klasse (Client.java) im aj_client Projekt (die keine AspectJ Natur hat).
    • hinzugefügt target.jar, logging.jar (und log4j.jar) mit der Java Build Path of aj_client und lief es.

Client.java enthält eine einzige Methode:

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

Wenn er gestartet wird, dies nicht mit einem 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

Um dies zu adressieren, modifizierte ich die .classpath von aj_client so es auf sie aspectjrt hat (durch manuelles Hinzufügen der AspectJ Runtime Library Classpath Container zum .classpath) und reran, das Programm ausführt und Ausgänge die Logging-Anweisungen:

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

Die .classpath Datei für aj_client sieht wie folgt aus:

<?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>

Ich habe auch versucht, in meiner Maven-Repository und Eclipse-Plugin, um meine aspectjrt zeige, mit dem gleichen Ergebnis (das Log-Meldungen ausgegeben wurden), das heißt ersetzen:

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

mit

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

oder

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

bewiesen hat, dass der Logging-Code gewebt ist, ging ich zurück und änderte Logging.aj GETLOG () zu verwenden. Info () ruft wieder, und fand die Logging-Anweisungen werden nicht mehr ausgegeben. Um dies zu beheben Ich habe eine log4j.xml Konfigurationsdatei (nur die Wurzel appender Angabe)

<?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>

Dies führte in der folgenden Ausgabe:

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

Hinweis: Sie müssen vorsichtig sein, um sicherzustellen, Sie have gereinigt, gebaut und exportiert logging.jar vor der Reinigung, Bau und Export von target.jar, dann reinigen Sie das Client-Projekt. Wenn Sie den Auftrag überhaupt verhunzen werden Sie nicht übereinstimmen Inhalt erhalten.


Zusammenfassung

So ist es, so lange Ihr Client-Projekt erscheint verweist auf eine „target.jar“, die mit AspectJ (so wurde die Logging.aj gewebt) gebaut wurde, und Sie haben einen aspectjrt.jar auf classpath und Sie haben konfiguriert log4j richtig die Protokollierung ausgegeben.

Sie können die aspectjrt Abhängigkeit von entweder den Classpath Container hinzufügen oder indem Sie den Pfad zu einem kompatiblen aspectjrt.jar Angabe

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top