如何修改我的 AspectJ 代码以适用于任何类?

问题描述 投票:0回答:1

如何修改 AspectJ 代码以创建可应用于包中任何类的通用方面,而不是仅限于“Main”等特定类名?

package org.mazouz.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Aspect
public class AspectJAspect {

    private static final String CSV_FILE_PATH = "/home/hadoop/Documents/AspectJ/output1.csv";
    private static final List < String > logEntries = new ArrayList < > ();
    private static boolean constructorExecuting = false;
    private static long aspectStartTime; // Variable to store the start time of the aspect
    private static int lineNumber = 1; // Start line number from 1

    // Pointcut to capture any method execution within the Main class
    @Pointcut("execution(* org.mazouz.aop.Main.*(..))")
    public void anyMethodExecution() {}

    // Pointcut to capture constructor execution within the Main class
    @Pointcut("execution(org.mazouz.aop.Main.new(..))") //Matches any constructor signature
    public void constructorExecution() {}

    // Pointcut to capture any field update within methods of the Main class
    @Pointcut("set(* org.mazouz.aop.Main.*) && within(org.mazouz.aop.Main)")
    public void fieldUpdate() {}

    // Advice triggered before entering the main method
    @Before("execution(public static void org.mazouz.aop.Main.main(String[]))")
    public void beforeMainMethod(JoinPoint joinPoint) {
        aspectStartTime = System.currentTimeMillis(); // Capture start time of the aspect
        addLogEntry("System Start", "", joinPoint); // Provided log line before entering the main method
        addLogEntry("Thread Start", "main", joinPoint); // Provided log line for thread start after "System Start"
        addLogEntry("Type Load", "class=java.lang.Object", joinPoint);
        // Retrieve class name dynamically and pass it to the addLogEntry method
        String className = joinPoint.getSignature().getDeclaringTypeName();
        className = className.substring(className.lastIndexOf('.') + 1); // Extract only the class name
        addLogEntry("Type Load", " class=" + className, joinPoint);
    }

    // Advice triggered before entering the constructor
    @Before("constructorExecution()")
    public void beforeConstructorExecution(JoinPoint joinPoint) {
        String constructorName = joinPoint.getSignature().getName();
        addLogEntry("Constructor Entry", constructorName, joinPoint);
        constructorExecuting = true;
    }

    // Advice triggered after exiting the constructor
    @After("constructorExecution()")
    public void afterConstructorExecution(JoinPoint joinPoint) {
        String constructorName = joinPoint.getSignature().getName();
        addLogEntry("Constructor Exit", constructorName, joinPoint);
        constructorExecuting = false;
    }

    // Advice triggered before any method execution within the Main class
    @Before("anyMethodExecution()")
    public void beforeMethodExecution(JoinPoint joinPoint) {
        addLogEntry("Method Entry", joinPoint.getSignature().getName(), joinPoint);
    }

    // Advice triggered after any field update within methods of the Main class
    @After("fieldUpdate()")
    public void afterFieldUpdate(JoinPoint joinPoint) {
        String fieldName = joinPoint.getSignature().getName();
        Object newValue = joinPoint.getArgs()[0];
        if (constructorExecuting) {
            addLogEntry("Field Write in Constructor", fieldName + " updated to " + newValue, joinPoint);
        } else {
            addLogEntry("Field Write", fieldName + " updated to " + newValue, joinPoint);
        }
    }

    // Advice triggered after any method execution within the Main class
    @After("anyMethodExecution()")
    public void afterMethodExecution(JoinPoint joinPoint) {
        addLogEntry("Method Exit", joinPoint.getSignature().getName(), joinPoint);
    }

    // Helper method to add log entries to the list
    private synchronized void addLogEntry(String event, String additionalInfo, JoinPoint joinPoint) {
        String threadName = Thread.currentThread().getName();
        int line = lineNumber++;
        String logEntry;

        String fileName;
        int lineNumber;

        if (joinPoint.getSourceLocation() != null) {
            fileName = joinPoint.getSourceLocation().getFileName();
            lineNumber = joinPoint.getSourceLocation().getLine();
        } else {
            // Handle null source location
            fileName = "Unknown";
            lineNumber = -1;
        }

        if (line > 4) {
            logEntry = "\"" + threadName + "\",\"" + line + "\",\"" + fileName + ":" + lineNumber + "\",\"" + event + "\",\"" + additionalInfo + "\"";
        } else {
            logEntry = "\"" + threadName + "\",\"" + line + "\",\"SYSTEM\",\"" + event + "\",\"" + additionalInfo + "\"";
        }
        logEntries.add(logEntry);
    }


    // Helper method to write all log entries to the file
    private synchronized void writeLogEntriesToFile() {
        try (FileWriter writer = new FileWriter(CSV_FILE_PATH)) {
            for (String logEntry: logEntries) {
                writer.append(logEntry);
                writer.append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // Advice triggered after the main method exits
    @After("execution(public static void org.mazouz.aop.Main.main(String[]))")
    public void afterMainMethod(JoinPoint joinPoint) {
        writeLogEntriesToFile();
        long aspectEndTime = System.currentTimeMillis(); // Capture end time of the aspect
        long aspectExecutionTime = aspectEndTime - aspectStartTime; // Calculate aspect execution time
        System.out.println("Aspect execution time: " + aspectExecutionTime + " milliseconds");
    }
}

Main.java

package jvmti;
public class Main {
    public static int staticVariable;
    public int a;
    public int b;
    public int c;
    public int d;
    public int e;

    public Main(int d, int e) {
        this.d = d;
        this.e = e;
    }

    public static void main(String[] args) {
        Main aop = new Main(5, 10);
        aop.methodA(5);
        aop.methodB(6);
        aop.methodC(7);
        Main.updateStaticVariable(8);
    }

    public void methodA(int value) {
        a = value;
        a = 20;
    }

    public void methodB(int value) {
        b = value;
        c = 15;
    }

    public void methodC(int value) {
        d = value;
        e = 25;
    }

    public static void updateStaticVariable(int value) {
        staticVariable = value;
    }
}

如何修改我的方面代码,使其足够通用,可以适用于包中的任何类,而不是仅限于“Main”等特定类名称?此外,当尝试进行此修改(试图使方面通用)时,我遇到了以下错误。

我该如何解决它才能成功实现通用方面

Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class org.mazouz.aop.AspectJAspect
    at org.mazouz.aop.Main.main(Main.java:23)
    Caused by: java.lang.ExceptionInInitializerError: Exception  org.aspectj.lang.NoAspectBoundException: org.mazouz.aop.AspectJAspect [in thread "main"]
    at org.mazouz.aop.AspectJAspect.aspectOf(AspectJAspect.aj:1)
    at org.mazouz.aop.AspectJAspect.<clinit>(AspectJAspect.aj:17)
    at org.mazouz.aop.Main.main(Main.java:18)
java aop aspectj trace pointcut
1个回答
0
投票

关于问题1,你检查过AspectJ文档吗?例如:

至于

NoClassDefFoundError
,我无法确定,但也许你尝试过这样的事情:

  • execution(* *(..)) && within(org.mazouz..*)
  • execution(new(..)) && within(org.mazouz..*)

这会重现您的错误。因为你的方面位于同一个基础包中,所以你需要排除它以避免 iut 尝试编织自身,这在某些情况下很好,anbd 使 AspectJ 如此强大,但你想在这里避免:

  • execution(* *(..)) && within(org.mazouz..*) && !within(*..*Aspect)
  • execution(new(..)) && within(org.mazouz..*) && !within(*..*Aspect)
© www.soinside.com 2019 - 2024. All rights reserved.