Aspectj pointcuts при назначении объектной переменной

Я хотел бы создать pointcut в следующем примере класса всякий раз, когда назначается переменная. Так, например, в методе method1(int number) для this.x устанавливается значение int. Я понимаю, что в этом случае я мог бы просто сделать pointcut для метода1, а затем узнать, какое новое значение x использует отражение. Однако мне было интересно, есть ли способ сделать pointcut на строке this.x = number, чтобы мой pointcut срабатывал, например, до завершения функции?

public class Sample {
private int x;

public void method1(int number) {
    this.x = number;
}

public int getX() {
    return this.x;
}

public void method1(int number, String value) {
    this.x = number;
}

public void method2(String value) {
    this.x = 105;
}
}

person dinamix    schedule 29.10.2016    source источник
comment
Вы не можете сделать pointcut для конкретной строки кода. Только по методам.   -  person Heri    schedule 29.10.2016


Ответы (1)


Вы можете сделать это с помощью:

  • привилегированный аспект:

    import java.lang.reflect.Field;
    import org.aspectj.lang.reflect.FieldSignature;
    
    public privileged aspect FieldChangeMonitorAspect {
    
        void around(Sample sample): set(int Sample.x) && target(sample) {
            FieldSignature fieldSignature = (FieldSignature) thisJoinPoint.getSignature();
            Field field = fieldSignature.getField();
    
            int oldValue = sample.x;
            int newValue = ((Integer)thisJoinPoint.getArgs()[0]).intValue();
            proceed(sample);
            int actualNewValue = sample.x;
    
            System.out.printf("changed field %s: old value=%d, new value=%d, "
                    + "actual new value=%d\n", 
                    field, oldValue, newValue, actualNewValue);
        }
    
    }
    
  • непривилегированный аспект с использованием отражения:

    import java.lang.reflect.Field;
    import org.aspectj.lang.reflect.FieldSignature;
    
    public aspect FieldChangeMonitorAspectWithReflection {
    
        void around(Sample sample): set(int Sample.x) && target(sample) {
            FieldSignature fieldSignature = (FieldSignature) thisJoinPoint.getSignature();
            Field field = fieldSignature.getField();
            try {
                Object oldValue = field.getInt(sample);
                Object newValue = thisJoinPoint.getArgs()[0];
                proceed(sample);
                Object actualNewValue = field.get(sample);
    
                System.out.printf("changed field %s: old value=%d, new value=%d, "
                        + "actual new value=%d\n", 
                        field, oldValue, newValue, actualNewValue);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    
    }
    

Первая (привилегированная) версия рекомендуется, когда вам нужно отслеживать известное поле известного типа, потому что она быстрее, так как не использует отражение. Однако, когда вам нужно отслеживать поля, которые неизвестны на момент написания (например, помеченные аннотацией), или есть несколько полей, которые вы хотите отслеживать, возможно, нескольких типов, может пригодиться вторая версия.

Не то чтобы newValue и actualNewValue всегда должны иметь одно и то же значение, но newValue доступно до изменения значения поля, а actualNewValue можно получить только после изменения значения поля.

person Nándor Előd Fekete    schedule 29.10.2016