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

Aspect Oriented Programming

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Aspect Oriented Programming

Avatar for Mariusz Gil

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