Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Aspect Oriented Programming

Aspect Oriented Programming

Mariusz Gil

August 17, 2019
Tweet

More Decks by Mariusz Gil

Other Decks in Programming

Transcript

  1. Aspect oriented
    Mariusz Gil
    @mariuszgil
    Programming

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. AOP
    Paradigm

    View Slide

  6. https://www.cs.ubc.ca/~gregor/papers/kiczales-ECOOP1997-AOP.pdf

    View Slide

  7. View Slide

  8. Domain
    application
    infrastructure

    View Slide

  9. Domain
    application
    infrastructure

    View Slide

  10. Domain
    application
    infrastructure

    View Slide

  11. Domain
    application
    infrastructure
    Domain
    Domain
    application
    infrastructure

    View Slide

  12. Feature #1 Feature #2 Feature #3
    non-Feature need #1
    non-Feature need #2
    non-Feature need #3
    non-Feature need #4

    View Slide

  13. Feature code
    Logging
    auth
    Feature code
    Transactional
    Feature code
    Logging

    View Slide

  14. Feature code
    Aspect
    Feature code
    Logging
    Feature code
    Transactional
    Feature code
    Logging
    Aspect
    Aspect
    auth

    View Slide

  15. Feature code
    Feature code
    Logging
    Feature code
    Transactional
    Feature code
    Logging
    Feature code
    Logging
    Feature code
    Transactional
    Feature code
    Logging
    Aspect
    Aspect
    Aspect
    auth auth

    View Slide

  16. live Demo

    View Slide

  17. View Slide

  18. View Slide

  19. live Demo
    Explanation

    View Slide

  20. namespace Aspect;
    use Go\Aop\Aspect;
    use Go\Aop\Intercept\MethodInvocation;
    use Go\Lang\Annotation\Before;
    use Psr\Log\LoggerInterface;
    /**
    * Monitoring aspect
    */
    class LoggingAspect implements Aspect
    {
    /**
    * @var LoggerInterface
    */
    private $logger;
    /**
    * @param LoggerInterface $logger
    */
    public function __construct(LoggerInterface $logger)
    {
    $this->logger = $logger;
    }
    /**
    * @param MethodInvocation $invocation Invocation
    * @Before("execution(public EC\Handler\AddProductToCartHandler->__invoke(*))")
    */
    public function beforeMethodExecution(MethodInvocation $invocation)
    {
    $this->logger->info(
    ‚Calling Before Interceptor for: ' .
    $invocation .
    ' with arguments: ' .
    var_export($invocation->getArguments(), true)
    );
    }
    }

    View Slide

  21. namespace Aspect;
    use Go\Aop\Aspect;
    use Go\Aop\Intercept\MethodInvocation;
    use Go\Lang\Annotation\Before;
    use Psr\Log\LoggerInterface;
    /**
    * Monitoring aspect
    */
    class LoggingAspect implements Aspect
    {
    /**
    * @var LoggerInterface
    */
    private $logger;
    /**
    * @param LoggerInterface $logger
    */
    public function __construct(LoggerInterface $logger)
    {
    $this->logger = $logger;
    }
    /**
    * @param MethodInvocation $invocation Invocation
    * @Before("execution(public EC\Handler\AddProductToCartHandler->__invoke(*))")
    */
    public function beforeMethodExecution(MethodInvocation $invocation)
    {
    $this->logger->info(
    ‚Calling Before Interceptor for: ' .
    $invocation .
    ' with arguments: ' .
    var_export($invocation->getArguments(), true)
    );
    }
    }
    Advice

    View Slide

  22. namespace Aspect;
    use Go\Aop\Aspect;
    use Go\Aop\Intercept\MethodInvocation;
    use Go\Lang\Annotation\Before;
    use Psr\Log\LoggerInterface;
    /**
    * Monitoring aspect
    */
    class LoggingAspect implements Aspect
    {
    /**
    * @var LoggerInterface
    */
    private $logger;
    /**
    * @param LoggerInterface $logger
    */
    public function __construct(LoggerInterface $logger)
    {
    $this->logger = $logger;
    }
    /**
    * @param MethodInvocation $invocation Invocation
    * @Before("execution(public EC\Handler\AddProductToCartHandler->__invoke(*))")
    */
    public function beforeMethodExecution(MethodInvocation $invocation)
    {
    $this->logger->info(
    ‚Calling Before Interceptor for: ' .
    $invocation .
    ' with arguments: ' .
    var_export($invocation->getArguments(), true)
    );
    }
    }
    Advice
    Pointcut

    View Slide

  23. namespace Aspect;
    use Go\Aop\Aspect;
    use Go\Aop\Intercept\MethodInvocation;
    use Go\Lang\Annotation\Before;
    use Psr\Log\LoggerInterface;
    /**
    * Monitoring aspect
    */
    class LoggingAspect implements Aspect
    {
    /**
    * @var LoggerInterface
    */
    private $logger;
    /**
    * @param LoggerInterface $logger
    */
    public function __construct(LoggerInterface $logger)
    {
    $this->logger = $logger;
    }
    /**
    * @param MethodInvocation $invocation Invocation
    * @Before("execution(public EC\Handler\AddProductToCartHandler->__invoke(*))")
    */
    public function beforeMethodExecution(MethodInvocation $invocation)
    {
    $this->logger->info(
    ‚Calling Before Interceptor for: ' .
    $invocation .
    ' with arguments: ' .
    var_export($invocation->getArguments(), true)
    );
    }
    }
    Advice
    Pointcut
    Aspect

    View Slide

  24. namespace Aspect;
    use Go\Aop\Aspect;
    use Go\Aop\Intercept\MethodInvocation;
    use Go\Lang\Annotation\Before;
    use Psr\Log\LoggerInterface;
    /**
    * Monitoring aspect
    */
    class LoggingAspect implements Aspect
    {
    /**
    * @var LoggerInterface
    */
    private $logger;
    /**
    * @param LoggerInterface $logger
    */
    public function __construct(LoggerInterface $logger)
    {
    $this->logger = $logger;
    }
    /**
    * @param MethodInvocation $invocation Invocation
    * @Before("execution(public EC\Handler\AddProductToCartHandler->__invoke(*))")
    */
    public function beforeMethodExecution(MethodInvocation $invocation)
    {
    $this->logger->info(
    ‚Calling Before Interceptor for: ' .
    $invocation .
    ' with arguments: ' .
    var_export($invocation->getArguments(), true)
    );
    }
    }
    Advice
    Pointcut
    Aspect

    View Slide

  25. namespace Aspect;
    use Go\Aop\Aspect;
    use Go\Aop\Intercept\MethodInvocation;
    use Go\Lang\Annotation\Before;
    use Psr\Log\LoggerInterface;
    /**
    * Monitoring aspect
    */
    class LoggingAspect implements Aspect
    {
    /**
    * @var LoggerInterface
    */
    private $logger;
    /**
    * @param LoggerInterface $logger
    */
    public function __construct(LoggerInterface $logger)
    {
    $this->logger = $logger;
    }
    /**
    * @param MethodInvocation $invocation Invocation
    * @Before("execution(public EC\Handler\AddProductToCartHandler->__invoke(*))")
    */
    public function beforeMethodExecution(MethodInvocation $invocation)
    {
    $this->logger->info(
    ‚Calling Before Interceptor for: ' .
    $invocation .
    ' with arguments: ' .
    var_export($invocation->getArguments(), true)
    );
    }
    }
    Advice
    Pointcut
    Aspect
    Pointcut designator

    View Slide

  26. /**
    * @param MethodInvocation $invocation Invocation
    * @Before("execution(public EC\Handler\AddProductToCartHandler->__invoke(*))")
    */
    public function beforeMethodExecution(MethodInvocation $invocation)
    {
    $this->logger->info(
    ‚Calling Before Interceptor for: ' .
    $invocation .
    ' with arguments: ' .
    var_export($invocation->getArguments(), true)
    );
    }
    }
    Advice
    Pointcut
    Pointcut designator
    Method execution
    Property access
    Function execution
    Initialization
    Lexical point cuts
    Logical combinations
    execution(MemberModifiers ClassFilter[::|->]NamePattern(*))
    execution(public Example->method(*))
    execution(public Example->method1|method2(*))
    execution(* Example\Aspect\*->method*(*))
    execution(public **::staticMethods(*))
    access(MemberModifiers ClassFilter->NamePattern)
    access(public Example\Demo->test)
    access(* Example\Aspect\*->fieldName)
    access(protected **->someProtected*Property)
    @access(Demo\Annotation\Cacheable)
    execution(NamespacePattern(*))
    execution(**\file_get_contents())
    execution(Example\Aspect\array_*(*))
    initialization(NamespacePattern)
    initialization(Demo\Example)
    initialization(Demo\**)
    staticinitialization(NamespacePattern)
    staticinitialization(Demo\Example)
    staticinitialization(Demo\**)
    within(ClassFilter)
    within(Demo\Example)
    within(Demo\Annotation\Loggable)
    (Pointcut)
    Pointcut|Pointcut
    !Pointcut
    (access(* Demo->*) || access(* Another->*))
    !execution(public **->*(*))
    execution(* Demo->*(*)) && execution(public **->*(*))
    access(public Demo->foo) || access(public Another->bar)

    View Slide

  27. use Aspect\LoggingAspect;
    use Aspect\TimeTrackingAspect;
    use Go\Core\AspectKernel;
    use Go\Core\AspectContainer;
    use Monolog\Handler\StreamHandler;
    use Monolog\Logger;
    /**
    * Application Aspect Kernel
    */
    class ApplicationAspectKernel extends AspectKernel
    {
    /**
    * Configure an AspectContainer with advisors, aspects and pointcuts
    *
    * @param AspectContainer $container
    * @return void
    */
    protected function configureAop(AspectContainer $container)
    {
    $logger = $this->getLogger();
    $container->registerAspect(new LoggingAspect($logger));
    $container->registerAspect(new TimeTrackingAspect($logger));
    //…
    }
    //…
    }

    View Slide

  28. Program Flow
    Aspect
    Pointcut + advice
    Aspect
    Poin cut + advice
    Aspect
    Pointcut + advice
    Join points Join points Join points
    Target Target Target

    View Slide

  29. Weaving process
    Compile-time weaving runtime weaving

    View Slide

  30. import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.AfterThrowing;
    @Aspect
    public class AfterThrowingExample {
    @AfterThrowing(
    pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
    throwing="ex")
    public void doRecoveryActions(DataAccessException ex) {
    // ...
    }
    }
    https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/aop.html

    View Slide

  31. import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.ProceedingJoinPoint;
    @Aspect
    public class AroundExample {
    @Around("com.xyz.myapp.SystemArchitecture.businessService()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
    // start stopwatch
    Object retVal = pjp.proceed();
    // stop stopwatch
    return retVal;
    }
    }
    https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/aop.html

    View Slide

  32. @Aspect
    public class ConcurrentOperationExecutor implements Ordered {
    private static final int DEFAULT_MAX_RETRIES = 2;
    private int maxRetries = DEFAULT_MAX_RETRIES;
    private int order = 1;
    public void setMaxRetries(int maxRetries) {
    this.maxRetries = maxRetries;
    }
    public int getOrder() {
    return this.order;
    }
    public void setOrder(int order) {
    this.order = order;
    }
    @Around("com.xyz.myapp.SystemArchitecture.businessService()")
    public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
    int numAttempts = 0;
    PessimisticLockingFailureException lockFailureException;
    do {
    numAttempts++;
    try {
    return pjp.proceed();
    }
    catch(PessimisticLockingFailureException ex) {
    lockFailureException = ex;
    }
    } while(numAttempts <= this.maxRetries);
    throw lockFailureException;
    }
    }

    View Slide

  33. class LoggerAspect {
    @beforeMethod({
    classes: [ArticleCollection],
    methods: [ArticleCollection.prototype.getArticle, ArticleCollection.prototype.setArticle]
    })
    invokeBeforeMethod(meta: Metadata) {
    // meta.advisedMetadata == { bar: 42 }
    console.log(
    `Inside of the logger. Called ${meta.className}.${meta.method.name}
    with args: ${meta.method.args.join(', ‚)}.`
    );
    }
    }
    class ArticleCollection {
    getArticle(id: number) {...}
    setArticle(article: Article) {...}
    }
    https://github.com/mgechev/aspect.js

    View Slide

  34. module Aquarium
    class Echo
    def method_missing sym, *args
    p "Echoing: #{sym.to_s}: #{args.join(" ")}"
    end
    def respond_to? sym, include_private = false
    true
    end
    end
    end
    Aquarium::Aspects::Aspect.new :around,
    :calls_to => :method_missing,
    :for_type => Aquarium::Echo do |jp, obj, sym, *args|
    if sym == :log
    p "--- Sending to log: #{args.join(" ")}"
    else
    jp.proceed
    end
    end
    https://github.com/deanwampler/Aquarium

    View Slide

  35. View Slide

  36. View Slide

  37. Aspect oriented
    Mariusz Gil
    @mariuszgil
    Programming

    View Slide