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. Feature #1 Feature #2 Feature #3 non-Feature need #1 non-Feature

    need #2 non-Feature need #3 non-Feature need #4
  2. 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
  3. 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) ); } }
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. /** * @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)
  10. 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)); //… } //… }
  11. Program Flow Aspect Pointcut + advice Aspect Poin cut +

    advice Aspect Pointcut + advice Join points Join points Join points Target Target Target
  12. 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
  13. 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
  14. @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; } }
  15. 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
  16. 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