Безопасно ли применять более одного аспекта?

Предположим, что у нас есть два аспекта:

public aspect TestAspect {
    pointcut publicMethodExecuted(): execution(public !static * *(..));

    int around() : publicMethodExecuted() {
        System.out.println("Test string");
        Object[] args = thisJoinPoint.getArgs();
        System.out.println(args[0]);
        int original_return_value = proceed();
        return original_return_value * 100;
    }
}

public aspect AnotherTestAspect {
    pointcut anotherPublicMethodExecuted(): execution(public !static * *(..));

    int around() : anotherPublicMethodExecuted() {
        System.out.println("Another Test string");
        Object[] args = thisJoinPoint.getArgs();
        System.out.println(args[0]);
    }
}

Как вы можете видеть, эти два аспекта имеют абсолютно одинаковый смысл. Поэтому они перехватывают один и тот же вызов метода. Насколько это безопасно?

Пожалуйста, не предлагайте мне ставить все это в один и тот же аспект. Я спрашиваю о AspectJ принципы работы и потенциальные возможности.

2 ответа

Да.

Предположим, у вас есть этот класс:

public class TestClass
{
public static void main( String[] args )
{
    new TestClass().print();
}

public void print()
{
    System.out.println("Hello World");
}
}

И эти аспекты:

public aspect FirstAspect
{
public pointcut hello1() : execution(void TestClass.print());
void around() : hello1() {
    System.out.println("first");
    proceed();
    System.out.println("first after");
}
}

public aspect SecondAspect
{

    public pointcut hello2() : execution(void TestClass.print());
    void around() : hello2() {
        System.out.println("second");
        proceed();
        System.out.println("second after");
    }
}

Когда вы запускаете, получается следующий вывод:

first
second
Hello World
second after
first after

Ответ прост: да, но...

Проще говоря, AspectJ делает в основном переход от точки к точке и поиск, как сплести его, а затем, ну, вплетает. В случае двух точечных копий к одному и тому же методу, одна из точечных копий будет соткать, а затем другая соткать и будет в основном отменять это первое переплетение. Если второй pointcut продолжается!

Позвольте мне объяснить это на коротком примере. Предположим, у вас есть следующий класс:

public class TestClass {

     public static void main(String... args) {
        new TestClass().x();
     }

     public void x() {
         System.out.println("Hello, world!");
     }
}

Теперь давайте определим аспект:

public aspect FirstAspect {

     public pointcut hello1() : execution(void mypackage.TestClass.x());
     void around() : hello1() {
         System.out.println("first");
     }

}

Что произойдет, это то, что аспект будет плести метод x, в основном замените вызов x на метод, созданный AspectJ.

Теперь давайте предположим, что у нас есть другой аспект:

public aspect SecondAspect {

     public pointcut hello2() : execution(void mypackage.TestClass.x());
     void around() : hello2() {
         System.out.println("second");
     }

}

С потерей общности и чтобы быть последовательным, давайте предположим, что FirstAspect сплетен первым. На тот момент мы получили тот же результат, что и раньше. Но теперь AspectJ продолжается и сплетается SecondAspect, Он находит метод x() и заменяет его выполнение (или вызов, в зависимости от типа pointcut) новым методом, эффективно переопределяя предыдущее переплетение и оставляя его устаревшим (как ни странно, первый сотканный код остается, но бесполезен).

Однако если SecondAspectЗвонки proceed() в любой момент часть, на которую он пойдет, на самом деле будет первым переплетением. Это потому, что, поскольку это было сплетено, это то, что x делал в отношении AspectJ.

Попробуйте это. Вы увидите, что на самом деле оставлено только одно из меток: вы получите только один отпечаток: либо first или же second но не оба, если вы не продолжите, как таковой:

 System.out.println("second");
 proceed();

Даже не важно когда ты proceed()До тех пор, пока вы делаете:

 proceed();
 System.out.println("second");

Если вы хотите убедиться, какой точечный вырез сплетен первым, вы можете посмотреть на AspectJ precedence declaration,

Другие вопросы по тегам