March 09, 2020

#SpringAOP Part 2: Aspect Oriented Programming Interview Questions & Answers

How to declare aspect in Spring AOP?
 < bean id="myAspect" class="com.scrutiny.aop.MyAspect" >
   < !-- configure properties of aspect here -- >
 < /bean >


How to declare a pointcut in Spring AOP?
@Pointcut("execution(* update(..))")
private void customerUpdate {}
 
A pointcut declaration has four parts:
  • Matching Method Signature Patterns
  • Matching Type Signature Patterns
  • Matching Bean Name Patterns
  • Combining Pointcut Expressions
What are the Pointcut Designators supported by Spring AOP
  • execution: pointcut expression for matching method execution join points.
  • within: pointcut expression for matching to join points within certain types
  • this: pointcut expression for matching to join points where the bean reference is an instance of the given type
  • target: pointcut expression for matching to join points where the target object is an instance of the given type
  • args: pointcut expression for matching to join points where the arguments are instances of the given types
  • @target: pointcut expression for matching to join points where the class of the executing object has an annotation of the given type
  • @args: pointcut expression for matching to join points where the runtime type of the actual arguments passed have annotations of the given type
  • @within: pointcut expression for matching to join points within types that have the given annotation
  • @annotation: pointcut expression for matching to join points where the subject of the join point has the given annotation
Some examples of common pointcut expressions are:
  • the execution of any public method: execution(public * *(..))
  • the execution of any method with a name beginning with "set": execution(* set*(..))
  • the execution of any method defined by the PolicyService interface: execution(* com.scrutiny.service.PolicyService.*(..))
  • the execution of any method defined in the service package: execution(* com.scrutiny.service.*.*(..))
  • the execution of any method defined in the service package or a sub-package: execution(* com.scrutiny.service..*.*(..))
  • any join point (method execution only in Spring AOP) within the service package: within(com.scrutiny.service.*)
  • any join point (method execution only in Spring AOP) within the service package or a sub-package: within(com.scrutiny.service..*)
  • any join point (method execution only in Spring AOP) where the proxy implements the PolicyService interface: this(com.scrutiny.service.PolicyService)
  • any join point (method execution only in Spring AOP) where the target object implements the PolicyService interface: target(com.scrutiny.service.PolicyService)
  • any join point (method execution only in Spring AOP) which takes a single parameter, and where the argument passed at runtime is Serializable:
  • args(java.io.Serializable)
  • any join point (method execution only in Spring AOP) where the target object has an @Transactional annotation: @target(org.springframework.transaction.annotation.Transactional)
  • any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation: @within(org.springframework.transaction.annotation.Transactional)
  • any join point (method execution only in Spring AOP) where the executing method has an @Transactional annotation: @annotation(org.springframework.transaction.annotation.Transactional)
  • any join point (method execution only in Spring AOP) which takes a single parameter, and where the runtime type of the argument passed has the @Classified annotation: @args(com.xyz.security.Classified)
  • any join point (method execution only in Spring AOP) on a Spring bean named 'policyService': bean(policyService)
  • any join point (method execution only in Spring AOP) on Spring beans having names that match the wildcard expression '*Service': bean(*Service)
Writing Aspect using Aspect Oriented Programming
Let us create first Aspect using Aspect Oriented Programming. For this we will first add dependencies in pom.xml

##pom.xml
 < ?xml version="1.0" encoding="UTF-8"? >
 < project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
     < modelVersion > 4.0.0 < /modelVersion >

     < groupId > com.example < /groupId >
     < artifactId > AOPTest < /artifactId >
     < version > 0.0.1-SNAPSHOT < /version >
     < packaging > jar < /packaging >

     < name > AOPTest < /name >
     < description > Demo project for Spring Boot < /description >

     < parent >
         < groupId > org.springframework.boot < /groupId >
         < artifactId > spring-boot-starter-parent < /artifactId >
         < version > 1.5.10.RELEASE < /version >
         < relativePath / >
     < /parent >
     < properties >
         < project.build.sourceEncoding > UTF-8 < /project.build.sourceEncoding >
         < project.reporting.outputEncoding > UTF-8 < /project.reporting.outputEncoding >
         < java.version > 1.8 < /java.version >
     < /properties >
     < dependencies >
         < dependency >
             < groupId > org.springframework.boot < /groupId >
             < artifactId > spring-boot-starter < /artifactId >
         < /dependency >
         < dependency >
             < groupId > org.springframework < /groupId >
             < artifactId > spring-aspects < /artifactId >
             < version > 4.1.1.RELEASE < /version >
         < /dependency >
         < !-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -- >
         < dependency >
             < groupId > org.aspectj < /groupId >
             < artifactId > aspectjrt < /artifactId >
             < version > 1.8.10 < /version >
         < /dependency >
         < dependency >
             < groupId > org.springframework.boot < /groupId >
             < artifactId > spring-boot-starter-test < /artifactId >
             < scope > test < /scope >
         < /dependency >
         < dependency >
             < groupId > aopalliance < /groupId >
             < artifactId > aopalliance < /artifactId >
             < version > 1.0 < /version >
         < /dependency >
         < dependency >
             < groupId > cglib < /groupId >
             < artifactId > cglib < /artifactId >
             < version > 3.2.6 < /version >
         < /dependency >
         < dependency >
             < groupId > asm < /groupId >
             < artifactId > asm < /artifactId >
             < version > 3.3.1 < /version >
         < /dependency >
     < /dependencies >
     < build >
         < plugins >
             < plugin >
                 < groupId > org.springframework.boot < /groupId >
                 < artifactId > spring-boot-maven-plugin < /artifactId >
             < /plugin >
         < /plugins >
     < /build >
 < /project >

##We will create a class AOPMain which will have a main method. We will be instatiating the Spring context.
package com.test.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.test.aop.service.ShapeService;

public class AOPMain {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
        ShapeService shapeService=context.getBean("shapeService", ShapeService.class);
        System.out.println("*****AOPMain: Inside main(), the Shape circle name is "+shapeService.getCircle().getName());
    }
}

##Create Spring.xml
 < ?xml version="1.0" encoding="UTF-8"? >
 < beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd " >
     < aop:aspectj-autoproxy / >
     < bean name="traingle" class="com.test.aop.model.Traingle" >
         < property name="name" value="Traingle Name" / >
     < /bean >
     < bean name="circle" class="com.test.aop.model.Circle" >
         < property name="name" value="Circle Name" / >
     < /bean >
     < bean name="shapeService" class="com.test.aop.service.ShapeService"    autowire="byName" / >
     < bean name="loggingAspect" class="com.example.aspect.LoggingAspect" / >
 < /beans >

##Circle class
package com.test.aop.model;

public class Circle {
    private String name;
    //getters and setters
}

##Traingle class
package com.test.aop.model;

public class Traingle {
    private String name;
    //getters and setters
}

##Create ShapeService
package com.test.aop.service;

import com.test.aop.model.Circle;
import com.test.aop.model.Traingle;

public class ShapeService {

    private Circle circle;
    private Traingle traingle;

    //getters and setters
}

##Create a LoggingAspect, which will contain list of all the Aspects.
package com.example.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class LoggingAspect {

    /* The advice will run before the execution of getName() method.
     * In this case the advice will executed before calling any method with name getName()*/
    @Before("execution(public String getName())")
    public void getNameAdvice() {
        System.out.println("*****LoggingAspect: getNameAdvice is executed..");
    }
   
    /* If you want advice to execute only before executing a particular method in
     * a specific class then, you need to full path of the class before the method name.*/
    @Before("execution(public String com.test.aop.model.Traingle.getName())")
    public void getTraingleNameAdvice() {
        System.out.println("*****LoggingAspect: getTraingleNameAdvice is executed..");
    }

    /* If you want advice to execute every time a method which starts with get and
     * returns a String*/
    @Before("execution(public String get*())")
    public void getAllStringAdvice() {
        System.out.println("*****LoggingAspect: getAllAdvice is executed..");
    }

    /* If you want advice to execute every time a method which starts with get, irrespective of the return type*/
    @Before("execution(public * get*())")
    public void getAllAdvice() {
        System.out.println("*****LoggingAspect: getAllAdvice is executed..");
    }

    /*Suppose you want to execute two advice's before calling a particular method.
     * 1). You need to declare a methods (e.g forAllGetters() with a @PointCut
     * 2). Declare two advice's and instead of execution, write the name of method which has @PointCut annotation.
     */

    @Before("forAllGetters()")
    public void firstAdvice() {
        System.out.println("*****LoggingAspect: firstAdvice is executed..");
    }
    @Before("forAllGetters()")
    public void secondAdvice() {
        System.out.println("*****LoggingAspect: secondAdvice is executed..");
    }

    @Pointcut("execution(* get*())")
    public void forAllGetters()
    {}

    /*If you want to apply point cuts to all the methods of a particular class*/
    @Pointcut("within(com.test.aop.model.Traingle)")
    public void forAllMethodsOfClass()
    {}

    /*If you want to apply point cuts to all the methods inside a particular package/ sub package*/
    @Pointcut("within(com.test..*)")
    public void forAllMethodsPackages()
    {}
}

JoinPoints
If you want a advice to print a message depending on which method has actually triggered the advice, this can be done by JoinPoints. The JoinPoints has information about the actual method call, that has triggered the advice.

JoinPoints means, all the places in our code, where we can apply advice.

@Aspect
public class LoggingAspect {
    @Before("forAllMethodsOfCircle()")
    public void circleAdvice(JoinPoint joinPoint) {
        System.out.println("*****LoggingAspect: Circle Advice is executed: "+joinPoint.toString());
        //get Target, returns the object whose method us called which triggered the advice
        Circle circle=(Circle)joinPoint.getTarget();   
    }

    /*If you want to apply point cuts to all the methods of a particular class*/
    @Pointcut("within(com.test.aop.model.Circle)")
    public void forAllMethodsOfCircle()
    {}

    /*This will be called for all the methods which takes String as an argument and to get the argument which is passed.*/
    @Before("args(name)")
    public void stringArgumentMethods(String name)
    {
        System.out.println("*****LoggingAspect: methods with String argument:"+name);
    }
}

-K Himaanshu Shuklaa..

No comments:

Post a Comment