Metaprogramovanie / Pokročilé AOP

Sergej Chodarev

Metaprogramovanie 11

Aspektovo-orientované programovanie

Časť 2

Sergej Chodarev

Bodové prierezy (pointcuts)

  1. Kinded pointcuts – podľa druhu bodu spájania:
    • execution, call, get, set, handler, initialization, preinitialization, staticinitialization, adviceexecution
  2. Non-kinded pointcuts – ostatné bodové prierezy:
    • this, target, args, @this, @target, @args, @annotation
    • within, withincode, @within, @withincode
    • cflow, cflowbelow, if

Prierez podľa toku riadenia

Iba prvé volanie v rekurzií

public class Factorial {
    public long factorial(int n) {
        if (n == 0) {
            return 1;
        }
        return n * factorial(n – 1);
    }
}

Iba prvé volanie v rekurzií

pointcut factorial(int n)
    : call(long Factorial.factorial(int)) && args(n);

before(int n)
    : factorial(n) && !cflowbelow(factorial(int)) {
    System.out.println("Calculating factorial for " + n);
}

Zrušenie vstupu a výstupu

public aspect NoIOAspect {
    Object around() : 
        call(* java.io..*(..)) &&
            cflow(execution(@NoIO * *(..))) {
        return null;
	}
}

Prierez podľa lexikálnej štruktúry

Iba podtriedy

this(Typ) && !within(Typ)

Vynechanie aspektu

public aspect PrintRecAspect {
    pointcut printTest() : call(* println(..));

    before() : printTest() {
        System.out.println("In Advice ...");
    }
}

Riešenie

public aspect PrintRecAspect {
    pointcut printTest() : call(* println(..))
         && !within(PrintRecAspect);

    before() : printTest() {
        System.out.println("In Advice ...");
    }
}

Alternatívne riešenie

public aspect PrintRecAspect {
    pointcut printTest() : call(* println(..))
         && !cflow(adviceexecution());

    before() : printTest() {
        System.out.println("In Advice ...");
    }
}

Prierez podľa podmienky

Príklad: Cache

Riešenie

@AspectJ

@AspectJ

@Aspect
public class LoggingAspect {
    private Logger logger;
    public LoggingAspect() { logger = new Logger(); }

    @Pointcut(
        "execution(* Product.setPrice(..)) &&" +
        "this(product) && args(price)")
    public void priceChange(Product product, BigDecimal price) {
    }
    @Before("priceChange(product, price)")
    public void log(Product product, BigDecimal price) {
        logger.writeLog("Changed " + product.getPrice() +
                        " to " + price);
    }
}

Statické pretínanie

Intertype declarations (ITD)

public interface Nameable {
    public void setName(String name);
    public String getName();
    static aspect Impl {
        private String Nameable.name;
        public void Nameable.setName(String name) {
            this.name = name;
        }
        public String Nameable.getName() {
            return this.name;
        }
    }
}

Mixin

public interface NameableMixin extends Nameable {
    static aspect Impl {
        private String NameableMixin.name;
        ... implementácia
    }
}

Príklad: Observer

Inštancie aspektov

Inštancie aspektov

Asociácie aspektov

Získanie inštancie

Spring AOP

Spring AOP

Konfigurácia

Spring + AspectJ

Obmedzenia Spring AOP

Aspektové knižnice

Abstraktný aspekt

public abstract aspect AbstractTracing {
    public abstract pointcut traced();
    public abstract Logger getLogger();
    before() : traced() {
        getLogger().log(Level.INFO, "Before: " + thisJoinPoint);
    }
}

Dediaci aspekt

public aspect BankingTracing extends AbstractTracing {
    public pointcut traced() : execution(* banking..*.*(..));
    public Logger getLogger() {
        return Logger.getLogger("banking");
    }
}

Čánok

K. Ostermann, P. Giarrusso, C. Kästner, and T. Rendel, “Revisiting Information Hiding: Reflections on Classical and Nonclassical Modularity,” in ECOOP 2011, doi: 10.1007/978-3-642-22655-7_8

Ďalší zaujímavý článok F. Steimann, “The Paradoxical Success of Aspect-oriented Programming,” OOPSLA '06, doi: 10.1145/1167473.1167514

Záver

Relativity (M. C. Escher)