Аспектно-ориентированное программирование - что такое «cflow»? - PullRequest
32 голосов
/ 05 марта 2011

Я ссылался на ссылку AspectJ здесь , в которой говорится, что 'cflow' равен

cflow(Pointcut) - каждая точка соединения в поток управления каждой точки соединения P выбраны Pointcut, включая P Сам

Это не совсем понятно для меня, и мне было интересно, не могли бы кто-нибудь подробнее рассказать о значении cflow, пожалуйста? Зачем его использовать?

Спасибо, действительно.

1 Ответ

53 голосов
/ 05 марта 2011

cflow поможет вам проконсультировать весь поток управления. Давайте попробуем пример, у меня есть 4 маленьких класса

public class A {

    public static void methodA() {
        B.methodB();
    }

}

public class B {

    public static void methodB() {
        C.methodC();
        int a = 1;
        int b = 2;
        System.out.println( a + b );
    }

}

public class C {

    public static void methodC() {
        D.methodD();
    }

}

public class D {

    public static void methodD() {

    }

}

мой аспект:

public aspect CFlow {

    public pointcut flow() : cflow(call( * B.methodB() ) ) && !within(CFlow);

    before() : flow() {
        System.out.println( thisJoinPoint );
    }

}

и мой бегун (просто чтобы посмотреть, что происходит):

public class Test {

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

}

в моем pointcut вы могли видеть cflow(call( * B.methodB() ) ), поэтому я хочу настроить управление аспектами, начиная с вызова B.methodB, и когда вы запускаете тестовый класс, вы видите на консоли:

call(void test.B.methodB())
staticinitialization(test.B.<clinit>)
execution(void test.B.methodB())
call(void test.C.methodC())
staticinitialization(test.C.<clinit>)
execution(void test.C.methodC())
call(void test.D.methodD())
staticinitialization(test.D.<clinit>)
execution(void test.D.methodD())
get(PrintStream java.lang.System.out)
call(void java.io.PrintStream.println(int))
3

последняя строка не принадлежит аспекту, это просто из-за System.out.println внутри methodB. Все напечатанные показывают, что вы управляете потоком - цепочками методов и «событий» (выполнение, вызов, инициализация ...). Видите ли, я начал с класса Test, который вызывал methodA, но они не в «стеке», потому что нас интересовал methodB поток управления.

Если вы хотите получить этот стек, но без первой строки (вызывающей себя), вы можете попытаться определить

public pointcut flow() :  cflowbelow(call( * B.methodB() ) ) && !within(CFlow);

cflowbelow - еще один pointcut, который означает поток управления, исключая указанный (в нашем случае вызов B.methodB).

Будьте осторожны, добавив !within(_aspect_) в pointcut, иначе вы не получите ничего хорошего, кроме StackOverflowError. Это происходит потому, что cflow не может быть определен во время компиляции, а во время выполнения аспект также относится к потоку управления (поэтому он ведет к вечной рекурсии ...)

хорошо, представьте, что поток управления похож на стек вызовов, тогда вы получите представление об его использовании;)

...