Spring explains AOP aspect oriented programming

Posted by bubazoo on Wed, 13 Oct 2021 16:16:06 +0200

Chapter 3 AOP aspect oriented programming

1. Problems caused by adding functions.

In the source code, the functions added in the business method.

1) The source code may change a lot.

2) There are many duplicate codes.

3) Code is difficult to maintain.

2. AOP concept

2.1 what is AOP

AOP (aspect oriented programming): Aspect Oriented Programming

Aspect: refers to the aspect, and the functions added to the business method are called the aspect. Facets are generally non business functions, and facet functions are generally reusable. For example, log function, transaction function, permission check, parameter check, statistics, etc.

Orient: face, face.

Programming: programming.

How to understand aspect oriented programming?

The application of design and development with section as the core.

1) When designing a project, find out the function of the section.

2) Arrange the execution time and position of the section.

3. Role of AOP

1) Reuse slice functions.

2) Let developers focus on business logic. Improve the efficiency of development.

3) Decouple business functions from other non business functions.

4) Add functions to existing business methods without modifying the original code.

3. Terms in AOP

1) Aspect: aspect, which adds functions to business methods.

2) JoinPoint: connection point, the business method of connecting aspects. When this business method is executed, it will also execute faceted functions.

3) Pointcut: a pointcut is a collection of one or more join points. Indicates that when these methods are executed, the function of section can be added.

Indicates where the slice is executed.

4) Target: target object. Add the function of cutting to that object. This object is the target object.

5) Advice: Notification (enhanced), indicating the execution time of the aspect. Whether the slice is executed before or after the target method.

There are three important elements in AOP: aspect, pointcut and advice.

The understanding of this concept is: execute Aspect at the time of Advice and at the position of Pointcut

AOP is a dynamic idea. During the running of the program, create a service proxy. When using the proxy to execute methods, add the function of aspect. The proxy object exists in memory.

4. When to use AOP

You want to add some of the same functions to some methods. The source code cannot be changed. To add non business functions to business methods, AOP can also be used.

5. Realization of AOP technology idea

Use the framework to implement AOP. There are many frameworks to implement AOP. Two famous

1) Spring: the spring framework implements some functions in the idea of AOP. The implementation of AOP by spring framework is cumbersome and cumbersome.

2) Aspectj: independent framework, especially AOP. Belongs to Eclipse

6. Implement AOP using Aspectj framework

The Aspectj framework can implement AOP using annotations and xml configuration files.

6.1 notices

Aspectj represents the aspect execution time, with Advice. This notification can be represented by annotations. Say five annotations, which represent the five execution times of the section. These annotations are called notification annotations.

@Before: pre notification.

@AfterReturning: Post notification.

@Around: surround notification.

@AfterThrowing: exception notification.

@After: final notification.

6.2 Pointcut position

Pointcut is used to represent the execution position of the aspect, and the pointcut expression in Aspectj is used.

Pointcut expression syntax: execution (definition of method)

Execution (access permission method return value method declaration (parameter) exception type)

ch07-aspectj-before:use aspectj-before:use aspectj Annotation of the framework to realize pre notification
 Implementation steps:
1.newly build maven project
2.modify pom.xml Join dependency
    spring-context Dependence, spring-aspects Dependent (usable) aspectj Functions of the framework)
    junit
3.Create business interfaces and implementation classes.

4.Create a class called facet class, which is a common class
    1)Add on top of the class@Aspect
    2)Define a method in a class that represents the function of the slice.
      Add above the method Aspect Notification annotations in the framework, for example@Before(value="Pointcut expression")

5.establish spring Configuration file.
  1)Declare target object
  2)Declare facet class objects
  3)Declare automatic proxy generator
  
6.Create a test class and add the function of facet when testing the execution of the target method.   

6.3 advance notice

applicationContext.xml

    Declare automatic proxy generator: the purpose is to create a proxy for the target object (that is, the proxy in the 06 project) ServiceProxy)
        call aspectj Functions in the framework, looking for Spring All target objects in the container,
        Add each target object to the function in the facet class to generate an agent.
        The proxy object is the target object in the modified memory, and the target is the proxy object( ServiceProxy)

-->
    <aop:aspectj-autoproxy/>

Section class


* @Aspect: Annotation of section class.
 *    Location: on top of a class
 *    Function: indicates that the current class is a faceted class.
 *
 *    Facet class: a class representing facet functions.
* */
@Aspect
public class MyAspect {
//    Define the method to represent the specific function of the section
    
    * Definition of pre notification method
     * 1)The method is public
    *  2) The method is void
     *  3)Method name customization
     *  4)Method can have parameters, if any JoinPoint
     *      Or not.
    * */

    
    * @Before: Before advice 
    *     Properties: value A pointcut expression that represents the execution position of the slice.
    *           In this method, the function of section will be executed at the same time.
    *     Location: above the method
    *
    *     characteristic:
    *       1)Execution time: execute before the target method.
    *       2)Does not affect the execution of the target method.
    *       3)The execution result of the target method is not modified.
    * */
//    @Before(value = "execution(public void com.sunny.service.impl.SomeServiceImpl.doSome(String, Integer))")
//    @Before(value = "execution(void com.sunny.service.impl.SomeServiceImpl.doSome(String, Integer))")
//    @Before(value = "execution(* *..doSome(..))")
    /**
    * The notification method in the aspect class can have parameters
    * JoinPoint It must be him.
     *
     * JoinPoint:Represents the business Method being executed. It is equivalent to the Method in reflection
     *      Usage requirements: must be the first in the parameter list.
     *      Function: get the information of method execution, such as method name and parameter set.
    * */
    @Before(value = "execution(* *..do*(..))")
    public void myBefore2(JoinPoint jp){

//        Gets the definition of the method
        System.out.println("In the pre notification, get the definition of the target method:"+jp.getSignature());
        System.out.println("In the pre notification, get the method name=="+jp.getSignature().getName());

//        Get method execution time parameters
        Object[] args = jp.getArgs();
//        All the parameters of the method are stored in the array
        for (Object obj:args){
            System.out.println("Pre notification, get the parameters of the method:"+obj);
        }

        String methodName = jp.getSignature().getName();
        if("doSome".equals(methodName)){
            //Section code
            System.out.println("doSome Output log: pre notification, aspect function, which is executed before the target method:"+new Date());
        }else if ("doOther".equals(methodName)){
            System.out.println("doOther Pre notification, as the method name and parameter record.");
        }

    }

}
public class MyTest {
    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);

        SomeService service = (SomeService) ctx.getBean("someService");

        service.doThird();


    }

}

6.4 post notification @ AfterReturning

@ AfterReturning: executed after the target method

package com.sunny.handle;

@Aspect
public class MyAspect {
//    Define the method to represent the specific function of the section
    
    * Definition of post notification method
     * 1)The method is public
    *  2) The method is void
     *  3)Method name customization
     *  4)The method has parameters and is recommended Object type
    * */


    
    * @AfterReturning:Post notification
    *       Properties: value Pointcut expression
     *           returning A custom variable that represents the return value of the target method.
     *                     The custom variable name must be the same as the formal parameter name of the notification method.
     *      Location: above the method
     *
     * characteristic:
     *  1.Executed after the target method.
     *  2.The execution result of the target method can be obtained.
     *  3.Does not affect the execution of the target method
     *
     *  Parameters of the method:
     *      Object res: Represents the return value of the method, using res receive doOther The result of the call.
     *      Object res = doOther();
     *
     *   Execution order of post notification
     *   Object res = SomeServiceImpl.doOther(..);
     *   myAfterReturning(res);
     *
     *   reflection:
     *      1.doOther Method returns String,Integer,Long And other basic types.
     *          In post notification, returning the modified value does not affect the result of the last call of the target method.
     *      2.doOther The result returned is the object type, for example Student.
     *        In the post notification method, modify this Student Does the attribute value of the object affect the last call structure?
    * */
    
//    JoinPoint must be the first parameter
    @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",returning = "res")
    public void myAfterReturning(JoinPoint jp,Object res){

//        Modify the return value of the target method.
        if(res!= null){
            res = "Hello Aspectj";
        }
        System.out.println("Post notification, executed after the target method. The execution results can be obtained:"+res);
        //What's the use of Object res
        if("abcd".equals(res)){
            System.out.println("Make different enhancements according to different return values");
        }else if("add".equals(res)){
            System.out.println("doOther I added the database, and I backed up the data");
        }
    }
}

six 5@Around Surround notification

@Around(value = "pointcut expression"

Using surround notification is to call the notification method of the aspect class.

@Aspect
public class MyAspect {
    
     * Definition of surround notification method
     * 1)The method is public
     *  2) The method must have a return value, which is recommended Object type
     *  3)Method name customization
     *  4)Method must have ProceedingJoinPoint parameter
     * */

    
    * @Around : Around Advice 
     *   Properties: value Pointcut expression
     *   Location: above the method definition
     *
     * Return value: Object , Indicates that you want to get the execution result when calling the target method (not necessarily the return value of the target method itself)
     * Parameters: ProceedingJoinPoint: Equivalent to reflection Method
     *          Function: to execute the target method, equal to Method.invoke()
     *
     *          public interface ProceedingJoinPoint extends JoinPoint
     *
     * characteristic:
     *  1.Enhancements can be made before and after the target method
     *  2.Whether the control target method is implemented
     *  3.Modify the execution result of the target method.
     *
    * */
    @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("A circular notification was executed myAround method");

//        Gets the parameter value when the method executes
        String name = "";
        Object args [] = pjp.getArgs();

        if(args!= null&& args.length>0){
            Object arg = args[0];
            if(arg != null){
                name = (String)arg;
            }
        }

        Object methodReturn = null;

        System.out.println("The wrap notification is executed and the log time is output before the target method=="+new Date());

//        Execute the target method ProceedingJoinPoint, indicating doFirst
        methodReturn  = pjp.proceed();//method.invoke() indicates the doFirst() method itself

        if("lisi".equals(name)){
            methodReturn = pjp.proceed();
            //, method. Invoke(), indicating that the doFirst() method itself is executed
        }


        if(methodReturn != null){
            methodReturn = "In the surround notification, modify the original execution result of the target method";
        }

        System.out.println("Around notification, after the target method, transaction submission and function are added");

//        Returns the execution result of the target method. It has not been modified.
        return methodReturn;
    }
}

6.6 @AfterThrowing exception notification

Syntax @ AfterThrowing(value = "pointcut expression", throwing = "custom variable")

@Aspect
public class MyAspect {
 
     * Definition of exception notification method
     * 1)The method is public
     *  2) Method has no return value, yes void
     *  3)Method name customization
     *  4)Method has parameters that are Exception
     * */

    
    * @AfterThrowing :Exception notification
     *      Properties: value Pointcut expression
     *           throwing A custom variable that represents the exception thrown by the target method.
     *                    The variable name must be the same as the formal parameter name of the notification method
     *      Location: above the method
     *characteristic:
     *  1.It is executed after the target method throws an exception. If there is no exception, it will not be executed
     *  2.The exception information of the target method can be obtained.
     *  3.It is not an exception handler. You can get the notification of an exception, send e-mail and SMS to notify developers.
     *      As a monitor of the target method.
     *      
     *  Execution of exception notification
     *  try{
     *      SomeServiceImpl.doSecond(..)
     *  }catch(Exception e){
     *      myAfterThrowing(e);
     *  }
    * */




    @AfterThrowing(value = "execution(* *..SomeServiceImpl.doSecond(..))",throwing = "ex")
    public void myAfterThrowing(Exception ex){
        System.out.println("Exception notification is executed when the target method throws an exception. The reason for the exception is:"+ex.getMessage());
        /**
        * When an exception occurs, you can:
         * 1.Record the abnormal time, location and other information.
         * 2.Send e-mail, SMS and notify developers
         *
        * */
    }
}

6.7 @After final notice

Syntax: @ After(value = "pointcut expression")

package com.sunny.handle;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Date;

@Aspect
public class MyAspect {
    /**
     * Definition of exception notification method
     * 1)The method is public
     *  2) The method has no return value and is void
     *  3)Method name customization
     *  4)Method has no parameters
     * */

    /**
     * @After: Final notice
     *      Attribute: value pointcut expression
     *      Location: above the method
     * characteristic:
     *  1.Executed after the target method.
     *  2.Will always be executed.
     *  3.It can be used to finish the final work of the program, such as cleaning up temporary data, variables and memory
     *  
     *  Final notice
     *  try{
     *      SomeServiceImpl.doThird(..)
     *  }finally{
     *      myAfter();
     *  }
     * */
    @After(value = "execution(* *..SomeServiceImpl.doThird(..))")
    public void myAfter(){
        System.out.println("The final notice will always be executed");
    }
}

6.8 @Pointcut definition and management pointcut annotation

@Pointcut(value = "pointcut expression")

@Aspect
public class MyAspect {

    @Before(value = "mypt()")
    public void myBefore(){
        System.out.println("Pre notification, executed before the target method");
    }


    @After(value = "mypt()")
    public void myAfter(){
        System.out.println("The final notice will always be executed");
    }

    /**
     * @Pointcut: Define and manage pointcuts, not notification annotations
     *      Attribute: value pointcut expression
     *      Location: on top of a custom method, this method is regarded as an alias for the pointcut expression.
     *            In other notification annotations, you can use the method name to indicate the use of this pointcut expression
     *
     * */
    @Pointcut("execution(* *..SomeServiceImpl.doThird(..))")
    public void mypt(){
//        No code required
    }

    @Pointcut("execution(* *..SomeServiceImpl.doThird(..))")
    private void mypt1(){
//        No code required
    }
}

7 AOP summary

AOP is a dynamic technical idea, which aims to realize the decoupling of business functions and non business functions. Business functions are also independent modules, such as transaction functions, logs, etc. so that these transaction and log functions can be reused.

When the target method needs some functions, you can use aop technology to generate proxy objects during program execution without modifying or modifying the source code, execute business methods through agents, and add functions at the same time.

8. Practice

ch13-aop-homework:use aop Check the parameters of the method

requirement:
1.When addNumber The parameter of the method is not null When I was young.
2.When addNumber Method can only be executed when its parameter is greater than 0 addNumber()Calculate the sum of the three numbers.
3.If any parameter is null ,Or less than 0 addNumber The return result is -1
4.use aop do addNumber()Method.
package com.firewolf.handle;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 1.When the parameter of addNumber method is not null.
 * 2.When the parameter of addNumber method is greater than 0, addNumber() can be executed to calculate the sum of three numbers.
 * 3.If any parameter is null or less than 0, the return result of calling addNumber is - 1
 * 4.Use aop to check the parameters of addNumber() method.
 * */
@Aspect
public class MyAspect {
    boolean flag = false;
    @Pointcut(value = "execution(* *..NumberServiceImpl.addnumber(..))")
    private void pct(){

    }

//    The Around method executes before before, so before is not used to check parameters
    @Around(value = "pct()")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        Object object = null;
        Object[] args = pjp.getArgs();
        for(Object arg:args){
            Integer in = (Integer) arg;
            if(in==null||in < 0 ){

                flag =true;
            }
        }
        if(flag==false){
//            The parameters meet the requirements
            System.out.println("The parameters are consistent with the results");
            object = pjp.proceed();
        }else{
            System.out.println("The parameter does not match the result");
            object = -1;
        }

        return object;
    }

}
//Interface
package com.firewolf.service;

public interface NumberService {
    Integer addnumber(Integer n1,Integer n2,Integer n3);
}

//Test class
    @Test
    public void test01(){
        String config = "ApplicationContext.xml";
        ApplicationContext context =new ClassPathXmlApplicationContext(config);

        NumberService service = (NumberService) context.getBean("numberServiceImpl");

//        service.addnumber(1,2,3);
        System.out.println(service.addnumber(1,2,3));

        System.out.println(service.addnumber(-1,1,1));
        System.out.println(service.addnumber(null,1,1));

    }

applicationContext.xml

    <aop:aspectj-autoproxy/>

    <bean id="myAspect" class="com.firewolf.handle.MyAspect"/>
    <bean id="numberServiceImpl" class="com.firewolf.service.NumberServiceImpl"/>

PS: parameters cannot be checked with before because before is executed before around.

Ask only the hard work, not the harvest

Topics: Java Spring AOP