Aspect Oriented Programming

Aspect Oriented Programming

34be88398f623c109b61d23e8215bd23?s=128

Mariusz Gil

August 17, 2019
Tweet

Transcript

  1. Aspect oriented Mariusz Gil @mariuszgil Programming

  2. None
  3. None
  4. None
  5. AOP Paradigm

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

  7. None
  8. Domain application infrastructure

  9. Domain application infrastructure

  10. Domain application infrastructure

  11. Domain application infrastructure Domain Domain application infrastructure

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

    need #2 non-Feature need #3 non-Feature need #4
  13. Feature code Logging auth Feature code Transactional Feature code Logging

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

    code Logging Aspect Aspect auth
  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
  16. live Demo

  17. None
  18. None
  19. live Demo Explanation

  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) ); } }
  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
  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
  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
  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
  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
  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)
  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)); //… } //… }
  28. Program Flow Aspect Pointcut + advice Aspect Poin cut +

    advice Aspect Pointcut + advice Join points Join points Join points Target Target Target
  29. Weaving process Compile-time weaving runtime weaving

  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
  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
  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; } }
  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
  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
  35. None
  36. None
  37. Aspect oriented Mariusz Gil @mariuszgil Programming