Tuesday, December 8, 2015

Spring AOP (Aspect Oriented Programming)


AOP is commonly described as a way to implement "cross-cutting concerns"...which means a way to define, in one place, functionality that's needed in multiple places throughout an application's code. 

That's true, but aspects are also useful even if they'll only be applied in a single place. The point is that aspects are a way of separating some functionality from the thing that needs it....regardless of how many things need it. That is, you can use aspects to factor functionality out of methods when that functionality is not cohesive within the scope of the method it should be applied to. 

For example: Auditing is has nothing to do with transferring money from one account to another. But it needs to happen when that money is transferred. Do you put the auditing functionality directly in the transfer method? Or would you extract it into an aspect? 

That said, Spring itself uses aspects for things like transactions, security, caching, and those kinds of things.


The most common usage is where your application has cross cutting concerns i.e. a piece of logic or code that is going to be written in multiple classes/layers.

And this could vary based on your needs. Some very common examples of these could be:

Transaction Management
Logging
Exception Handling (especially when you may want to have detailed traces or have some plan of recovering from exceptions)
Security aspects
Instrumentation



Terms & Definitions

Concern: This is a battlefield, any interest area, any Use Case (in UML), something/some-area that interested you and that you want to change, like a classical use case as “payment”, “users managements” and many others.
Crosscutting concern: This a concern that can affect the entire application and should be centralized in one location in code as possible, such as “authentication” or “logging”.
Join Point: A point during the execution of a program, such as the execution of a method or the handling of an exception.
Aspect: Is a module that encapsulates a concern. An aspect is composed of Pointcuts, advice bodies, and inter-type declarations. In some approaches, an aspect may also contain classes and methods.
Pointcut: A predicate that matches Join Points.
Advice: Action taken by an Aspect at a particular Join Point in a desired moment - “before”, “after”, etc.

Pointcut :

Pointcut is a predicate that matches Join Points. This has a very similar syntax style like pattern matching (for Perl programmers) or like Regular Expressions. This predicate or expression matches, for example, a method with a certain name. Example (pointcut for all methods whose names begin with 'list'):

execution ( * adrabi.codeproject.*.GamesImpl.list*( .. ) )

All methods in the class GameImpl that have names starting with 'list' and has any type of parameter.

Firstly, this is a real example:

<aop:config> 
    <aop:pointcut id="gamesService" 
       expression="execution(* com.xyz.myapp.service.*.*(..))" /> 
</aop:config>



Before Advice:

We simulate a simple CRUD application for hardwares by using:

An interface for service called: HardwareService.java
A class for implementing the interface called: HardwareImpl.java
A simple class entity called: Hardware.java
A class for creating methods for Pointcuts called: HardwareServicePointcuts.java
And a class for executing the application called: Main.java
Plus Spring configuration file called: application.xml
with the objective to apply three Aspects for the Hardware service (HardwareImpl.java) in advice “before”. And we study the results, and each Aspect has a unique pointcut that uses a unique method in the Hardware service pointcuts (HardwareServicePointcuts.java). The pointcut's objectives are:

Pointcut for triggering method “beforeAnyMethodStartedWithList” within any method in the Hardware service, with a name beginning with 'list begin executing'.
Pointcut for triggering method “beforeRemove” within the method “remove” begins executing.
Pointcut for triggering method “beforeIfNotSaveMethod” within any method not named “save” in the Hardware service begins executing.
Are the objectives clear? Let's study the results and output, but before we do it, I'll paste here just the interested parts in the source:

public interface HardwareService
{
      /**
      * Save new Hardware
      * @param hw
      * @return
      */
      public Hardware save( Hardware hw );
   
      /**
      * Remove Hardware
      * @param hw
      */
      public void remove( Hardware hw );
   
      /**
      * Get Hardware by id
      * @param id
      * @return
      */
      public Hardware get(int id);
   
      /**
      * Get list of all Hardware
      * @return
      */
      public List<Hardware> listAll();
   
      /**
      * Get list of Hardware by vendor
      * @param vendor
      * @return
      */
      public List<Hardware> listByVendor(String vendor);
}

This is the Hardware service (HardwareService.java):

public class HardwareServicePointcuts
{
      /**
      * Pointcut for any method in bean Hardware service his name started with 'list'
      */
      public void beforeAnyMethodStartedWithList()
      {
        System.out.println("*** Some methods started with 'list' has " +
                           "begin executing now! ***");
      }
   
      /**
      * Pointcut for method remove only in bean Hardware serive
      */
      public void beforeRemove()
      {
        System.out.println("*** Method 'remove' has begin executing now! ***");
      }
   
      /**
      * Pointcut for any method not named 'save' in bean hardware service
      */
      public void beforeIfNotSaveMethod()
      {
        System.out.println( "*** Method 'save' hasn't begin executing yet! ***" );
      }
}

This is the method that will be triggered if the Pointcuts match.

<aop:config>
    <aop:aspect id="anyMethodStartedWithList" ref="hardwareServicePointcuts">
        <aop:before method="beforeAnyMethodStartedWithList"
            pointcut="execution(* adrabi.codeproject.*.*.*.HardwareImpl.list*(..) )" />
    </aop:aspect>

    <aop:aspect id="MethodRemove" ref="hardwareServicePointcuts">
        <aop:before method="beforeRemove"
           pointcut="execution(* adrabi.codeproject.*.*.*.
                     HardwareImpl.remove(adrabi.*.*.*.*.Hardware) )" />
    </aop:aspect>

    <aop:aspect id="notMethodSave" ref="hardwareServicePointcuts">
        <aop:before method="beforeIfNotSaveMethod"
           pointcut="!execution(* adrabi.codeproject.*.*.*.HardwareImpl.save(..) )" />
    </aop:aspect>
</aop:config>

And this is a configuration for Spring AOP. You will notice three Aspects. Each Aspect has an advice “before”, and for each Advice, there is a pointcut. Each pointcut tries to match something.

pointcut="!execution(*adrabi.codeproject.*.*.*.HardwareImpl.save(..) )"
Now we profile the application main (in the Main class, right click > in the context menu > click Profile As > Java Application):

public static void main(String[]$)
{
    //init Spring configuration
    ApplicationContext context =
      new ClassPathXmlApplicationContext("application.xml");
    HardwareService hds = (HardwareService) context.getBean("hardwareService");
 
    /*###############[ -- any method started with 'list' -- ]#################*/
    System.out.println("\n\n###############[ -- any method " +
                       "started with 'list' -- ]#################");
    //~
    List<Hardware> list = hds.listAll();
    for( Hardware h : list )
    {
                  System.out.println( h );
    }
    //~

    /*###############[ -- method named 'remove' -- ]#################*/
    System.out.println("\n\n###############[ -- method " +
                       "named 'remove' -- ]#################");
    //~
    hds.remove( hds.get(2) );
    //~
 
 
    /*###############[ -- method named 'save' -- ]#################*/
    System.out.println("\n\n###############[ -- method " +
                       "named 'save' -- ]#################");
    //~
    hds.save( new Hardware(4, 5454477877213l, "vendor #4") );
    for( Hardware h : list )
    {
                  System.out.println( h );
    }
    //~
}

After Advice :

We simulate a simple authentication system by using:

An interface for service called: AuthenticationService.java
A class for implementing the interface called: AuthenticationImpl.java
A class for creating the methods for the Pointcuts called: AuthenticationServicePointcuts.java
And a class for executing the application called: Main.java
Plus the Spring configuration file called: application.xml
With objectives similar to the advice “before”, we've just two Aspects and two Pointcuts:

Pointcut for triggering method “afterUsernameOrPassword” within the method “userName” or “password” has finished executing.
Pointcut for triggering method “afterLogout” within any method “logout” in Authentication service has finished executing.

public interface AuthenticationService
{
  /**
  * Setting a user name for authentication
  * @param userName
  */
  public void userName(String userName);

  /**
  * Setting a password for authentication
  * @param password
  */
  public void password(String password);

  /**
  * Try to log-in
  * @return
  */
  public boolean login();

  /**
  * Try to log-out
  * @return
  */
  public boolean logout();
}

This is the Authentication service:

public class AuthenticationServicePointcuts
{
  /**
  * Pointcut for methods userName() or password()
  */
  public void afterUsernameOrPassword()
  {
      System.out.println("*** username or password method has exected ***");
  }

  /**
  * Pointcut for method logout
  */
  public void afterLogout()
  {
      System.out.println( "*** you've logout now! see you later, bye! ***" );
  }
}

This is a method that will be triggered if Pointcuts match:

<aop:config>
    <aop:pointcut id="p_usernameOrPassword"
       expression="execution(* userName(..)) or execution(* password(..))" />
    <aop:pointcut id="p_logout" expression="execution(* logout())" />

    <aop:aspect id="afterUsernameOrPassword" ref="authServicePointcuts">
       <aop:after method="afterUsernameOrPassword" pointcut-ref="p_usernameOrPassword"/>
    </aop:aspect>

    <aop:aspect id="afterLogout" ref="authServicePointcuts">
       <aop:after method="afterLogout" pointcut-ref="p_logout"/>
    </aop:aspect>
</aop:config>

You can see two things have changed:

Firstly, we've created a separated Pointcut.
Secondly, in advice “after”, we don't use the parameter “pointcut” as advice “before” but has replaced it with “pointcut-ref”.
Also, you will notice in pointcut n°1 “usernameOrPassword”, I've used “or ”:

expression="execution(* userName(..)) or execution(* password(..))"

We profile the main application:

public static void main(String[]$)
{
    //init Spring configuration
    ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
    AuthenticationService auth = (AuthenticationService)context.getBean("authService");

    auth.userName("adrabi");
    auth.password("no-password");
    System.out.println( "Login results is : " + auth.login());
    System.out.println( "Logout results is : " + auth.logout());
}

And we get a nice output:

*** username or password method has exected ***
*** username or password method has exected ***
Login results is : true
*** you've logout now! see you later, bye! ***
Logout results is : true

Around Advice :

An interface for the service called: SerialService.java
A class for implementing the interface called: SerialImpl.java
A class for creating methods for Pointcuts called: SerialServicePointcuts.java
And a class for executing the application called: Main.java
Plus a Spring configuration file called: application.xml

With objectives similar to the advice “before”, we use two Pointcuts for cracking a serial number system:

Pointcut for triggering the method “aroundCheckSerialNumber” to replace the method “checkSerialNumber”.
Pointcut for triggering the method “aroundSendHasActived” to replace the method “sendSerialHasActived”.

public interface SerialService
{
  /**
  * Check serial number is valid
  * @param serial
  * @return
  */

  public boolean checkSerialNumber(String serial);

  /**
  * Send serial is actived to vendor
  */
  public void sendSerialHasActived();
}

This is the Serial service:

public class SerialServicePointcuts
{
  /**
  * Around and Stop "CheckSerialNumber" method to be executed
  *
  * @param joinPoint
  */
  public boolean aroundCheckSerialNumber( ProceedingJoinPoint joinPoint )
  {
    System.out.println( "*** The method [" + joinPoint.getSignature().getName() +
                        "] has been cracked ^_^ ***" );
    return true;
  }

  /**
  * Around and Stop "SendIsHasActived" method to be executed
  *
  * @param joinPoint
  */
  public void aroundSendHasActived(ProceedingJoinPoint joinPoint)
  {
    System.out.println( "*** The method [" +
                        joinPoint.getSignature().getName() +
                        "] has been cracked ^_^ ***" );
  }
}

This is a method that will be triggered if the Pointcuts match:

<aop:config>
    <aop:aspect id="aroundCheckSerialNumber" ref="serialServicePointcuts">
        <aop:around method="aroundCheckSerialNumber"
                pointcut="execution(* checkSerialNumber(..))"/>
    </aop:aspect>
    <aop:aspect id="aroundSendHasActived" ref="serialServicePointcuts">
        <aop:around method="aroundSendHasActived"
                pointcut="execution(* sendSerialHasActived(..))"/>
    </aop:aspect>
</aop:config>

This is our evil Spring AOP configuration ^_^ to crack the serial number system and to stop the serial number being sent to the vendor.

Now we profile the Main class:

public static void main(String[]$)
{
    //init Spring configuration
    ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
    SerialService serial = (SerialService) context.getBean("serialService");
 
    //serial for test 1893-5714-6364
    if( serial.checkSerialNumber(null) )
    {
        serial.sendSerialHasActived();
    }
}

And we get a very nice output:

*** The method [checkSerialNumber] has been cracked ^_^ ***
*** The method [sendSerialHasActived] has been cracked ^_^ ***







2 comments:

  1. Thanks for sharing this informative content , Great work
    Leanpitch provides online training in Agile coach during this lockdown period everyone can use it wisely.
    Certified agile coaching Bangalore

    ReplyDelete
  2. Thanks for sharing this informative content , Great work
    Creative Thinking for creating an impact!
    Product Thinking Community introduces PT Labs powered by Leanpitch
    Product thinking conference

    ReplyDelete

Java 9 and Java11 and Java17, Java 21 Features

 Java 9 and Java11 and Java17 features along with explanation and examples in realtime scenarios Here's a detailed breakdown of Java 9, ...