What Spring AOP Must Know about Aspect-Oriented Programming

Posted by swasheck on Wed, 04 Sep 2019 11:52:11 +0200

1. Overview

What is aspect-oriented programming?

Aspect-oriented programming is a programming paradigm (other common programming paradigms include process-oriented programming, object-oriented programming OOP, function-oriented programming, event-driven programming and Aspect-Oriented programming). It is not a programming language. Aspect-oriented programming can solve specific problems, but it can not solve them. All problems, it is a complement to object-oriented programming, not a substitute.

It can solve the problem of code repeatability to a large extent, and can achieve separation of concerns, such as functional requirements and non-functional requirements, so as to achieve centralized management, enhance the readability and maintainability of the code.

2. Common usage scenarios of AOP

Common usage scenarios in system development are

Permission control

Cache control

Transaction control

Audit logs

Performance monitoring

Distributed Tracking

Exception handling

3. Two main concerns of Spring AOP

      Pointcut express

Aspect expression mainly expresses how to find the logical point of the insertion of the aspect. Point cut expression provides a wealth of expressions to allow us to insert the aspect.

Five Advice s

After finding the entry point, there are five main ways to specify when to implant code, as follows:

          @Before Before advice

@ After(finally), post-notification, after the method has been executed

@ AfterReturning, return notification, after return value

@ AfterThrowing, exception notification, after throwing an exception

           @Around Around notification, surround notification contains all of the above types

The above two concerns conclude with a statement about where and when to do our code entry.

4. Common Section Expressions

1. within expression, matching methods under packages or classes

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * //Matching all methods in the ProductService class
 * @Pointcut("within(com.ruoli.service.ProductService)")
 * //Method of matching all classes under com.ruoli package and subpackage
 * @Pointcut("within(com.ruoli..*)")
 */
@Aspect
@Component
public class PkgTypeAspectConfig {
   @Pointcut("within(com.ruoli.service.sub.*)")
   public void matchType(){}

   @Before("matchType()")
   public void before(){
       System.out.println("");
       System.out.println("###before");
   }
}

2. Object Matching

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * //A method that matches the target object of an AOP object to a specified type, that is, an AOP proxy object of LogService
 * @Pointcut("this(com.ruoli.log.Loggable)")
 * //Method of matching the target object (not the object after aop proxy) that implements the Loggable interface
 * @Pointcut("target(com.ruoli.log.Loggable)")
 * //this DeclareParents(Introduction) can be intercepted
 * //target Do not intercept Declare Parents (Introduction)
 * //Method matching in all bean s ending with Service
 * @Pointcut("bean(*Service)")
 * Created by cat on 2016-12-04.
 */
@Aspect
@Component
public class ObjectAspectConfig {

   @Pointcut("bean(logService)")
   public void matchCondition(){}

   @Before("matchCondition()")
   public void before(){
       System.out.println("");
       System.out.println("###before");
   }
}

3. Method of parameter matching and configuration of specified parameters

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * //Matching any method that starts with find and has only one Long parameter
 * @Pointcut("execution(* *..find*(Long))")
 * //Match any method that starts with find and the first parameter is Long
 * @Pointcut("execution(* *..find*(Long,..))")
 * //Matching any method with only one Long parameter
 * @Pointcut("within(com.ruoli..*) && args(Long)")
 * //A Method of Matching the First Parameter of Long Type
 * @Pointcut("within(com.ruoli..*) && args(Long,..)")
 * Created by cat on 2016-12-04.
 */
@Aspect
@Component
public class ArgsAspectConfig {
   @Pointcut("args(Long,String) && within(com.ruoli.service.*)")
   public void matchArgs(){}

   @Before("matchArgs()")
   public void before(){
       System.out.println("");
       System.out.println("###before");
   }
}

4. Annotation Matching

There are mainly method-level annotations, class-level annotations and parameter-level annotations.

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * //Matching method annotated with AdminOnly annotations
 * @Pointcut("@annotation(com.ruoli.anno.AdminOnly) && within(com.ruoli..*)")
 * //Match the method // class level underneath the class marked with NeedSecured
 * @Pointcut("@within(com.ruoli.anno.NeedSecured) && within(com.ruoli..*)")
 * //Method //runtime level matching classes with NeedSecured and their subclasses
 * In the context of spring context, there is no difference between the two.
 * @Pointcut("@target(com.ruoli.anno.NeedSecured) && within(com.ruoli..*)")
 * //Method of matching incoming parameter classes with Repository annotations
 * @Pointcut("@args(com.ruoli.anno.NeedSecured) && within(com.ruoli..*)")
 * Created by cat on 2016-12-04.
 */
@Aspect
@Component
public class AnnoAspectConfig {

   @Pointcut("@args(com.ruoli.anno.NeedSecured) && within(com.ruoli..*)")
   public void matchAnno(){}

   @Before("matchAnno()")
   public void before(){
       System.out.println("");
       System.out.println("###before");
   }

}

5. execution expression

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * //Match any common method
 @Pointcut("execution(public * com.ruoli.service.*.*(..))")

 //Matching the non-parametric methods in Service classes under com.imooc packages and subpackages
 @Pointcut("execution(* com.ruoli..*Service.*())")

 //Method of matching any Service class with only one parameter under com.imooc package and subpackage
 @Pointcut("execution(* com.ruoli..*Service.*(*))")

 //Any method of matching any class under com.imooc package and subpackage
 @Pointcut("execution(* com.ruoli..*.*(..))")

 //Any method that matches the return value of String under com.imooc package and subpackage
 @Pointcut("execution(String com.ruoli..*.*(..))")

 //Matching exception
 execution(public * com.ruoli.service.*.*(..) throws java.lang.IllegalAccessException)

 * 
 */
@Aspect
@Component
public class ExecutionAspectConfig {

	@Pointcut("execution(public * com.ruoli.service..*Service.*(..) throws java.lang.IllegalAccessException)")
	public void matchCondition(){}

	@Before("matchCondition()")
	public void before(){
	 System.out.println("");
	 System.out.println("###before");
	}
}

5. Five examples of notification code

    

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.omg.CORBA.Object;
import org.springframework.stereotype.Component;

/**
 * @Before("matchAnno()")
 * @After("matchAnno())") //Equivalent to final
 * @AfterReturning("matchException()")
 * @AfterThrowing("matchException()")
 * @Around("matchException()")
 * @Before(value = "matchLongArg() && args(productId)")
 * public void beforeWithArgs(Long productId)
 * @AfterReturning(value = "matchReturn()",returning = "returnValue")
 * public void getReulst(Object returnValue)
 * 
 */
@Aspect
@Component
public class AdviceAspectConfig {

    /******pointcut********/

    @Pointcut("@annotation(com.ruoli.anno.AdminOnly) && within(com.ruoli..*)")
    public void matchAnno(){}

    @Pointcut("execution(* *..find*(Long)) && within(com.ruoli..*) ")
    public void matchLongArg(){}

    @Pointcut("execution(public * com.ruoli.service..*Service.*(..) throws java.lang.IllegalAccessException) && within(com.ruoli..*)")
    public void matchException(){}

    @Pointcut("execution(String com.ruoli..*.*(..)) && within(com.ruoli..*)")
    public void matchReturn(){}


    /******advice********/
    @Before("matchLongArg() && args(productId)")
    public void before(Long productId){
        System.out.println("###before,get args:"+productId);
    }
   @Around("matchException()")
   public java.lang.Object after(ProceedingJoinPoint joinPoint){
       System.out.println("###before");
       java.lang.Object result = null;
       try{
           result = joinPoint.proceed(joinPoint.getArgs());
           System.out.println("###after returning");
       }catch (Throwable e){
           System.out.println("###ex");
           //throw
           e.printStackTrace();
       }finally {
           System.out.println("###finally");
       }
       return result;
   }

}

Topics: Programming Java Spring