Detailed explanation of Java spring AOP (aspect oriented programming), java code learning case

Posted by kanikilu on Sat, 15 Jan 2022 17:36:34 +0100

1.SpringAOP

1.1 AOP introduction

In the software industry, AOP is the abbreviation of Aspect Oriented Programming, which means: Aspect Oriented Programming, a technology to realize the unified maintenance of program functions through precompiled mode and dynamic agent during operation. AOP is the continuation of OOP, a hot spot in software development, an important content in Spring framework, and a derivative paradigm of functional programming. AOP can isolate each part of business logic, reduce the coupling between each part of business logic, improve the reusability of program, and improve the efficiency of development.

AOP mainly uses dynamic agent mode to reduce program coupling and expand business functions

1.2 interpretation of terms

1). Connection point: a method joinPoint that users can extend
2). Pointcut: the method actually extended by the user (judge whether the method can enter the cutting plane) pointcut pointcut expression
3). Notice: concrete implementation of extension method @ before
4). Aspect: the process method function of applying notification to pointcuts is extended and fully configured (aspect = pointcut expression + notification method)

(Lao Wang was hungry and went to eat. He was struck to the heaven by thunder on the way. He ate flat peach, ginseng fruit and Tang monk.)

(the whole process = section, connection point = eat () / JoinPoint, entry point = being struck by lightning / pointcut, notification = entering the heaven to start eating)

1.3 notification type

1. @before: Execute before the target method executes
 ​	2.@afterReturning: Execute on return after target method execution
 ​	3.@afterThrowing: After the target method is executed,Execute when an exception is thrown
 ​	4.@after: Whether the program is executed successfully or not,Notice of final execution
 ​	5.@around: Notifications to be executed before and after the target method is executed(It perfectly embodies the dynamic agent mode),The most powerful, only surround notifications can control the execution of the target method

Summary of notification methods:
1. Surround notification is the first choice for business processing You can modify the execution track of the program (control the execution of the target method)
2. The other four notifications are generally used for program monitoring (monitoring system) record only

1.4 pointcut expression

Concept: when the program satisfies the pointcut expression, it can enter the aspect and execute the notification method

1.bean("bean ID") can only match one bean when intercepting according to beanId
2.within("package name. Class name") can use wildcard ***** to match multiple
Granularity: the above pointcut expression granularity is class level Coarse grained
3. Execution (return value type, package name, class name, method name (parameter list...))
Granularity: controls the level of method parameters Therefore, the particle size is fine The most commonly used
4. @ annotation (package name. Annotation name) only intercepts annotations
Granularity: an annotation is a tag that identifies the granularity of a method / attribute / class according to rules

1.5 AOP introduction case

1.5.1 import jar package

<?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>org.example</groupId>
<artifactId>spring_demo_9_aop</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>

    <!--Spring Core package-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.6</version>
    </dependency>

    <!--introduce SpringBean-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.6</version>
    </dependency>

    <!--introduce context package-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.6</version>
    </dependency>

    <!--Introduce expression jar package-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>5.3.6</version>
    </dependency>

    <!--Introduce log dependency-->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>

    <!--Import test package-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

    <!--introduce AOP package-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.3.6</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.3.6</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.9.6</version>
    </dependency>
</dependencies>
</project>

1.5.2 write UserService/userServiceImpl class

package com.jt.vo.aop;

public interface UserService {
    void  addUser();

    void  deleteUser();
}

import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("New user");
    }

    @Override
    @Cath  // Marked by annotation
    public void deleteUser() {
        System.out.println("delete user");
    }


}

Create annotation class

package com.jt.vo.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)  //Controls the lifecycle of annotations
//Annotation object, method valid, class valid Type
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
public @interface Cath {


}

1.5.4 configuration section class

Aspect = pointcut expression + notification method

package com.jt.vo.aop;

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

//1.AOP needs to be managed by Spring container
@Component
//2. Identify this class as AOP section
//  The Spring container does not recognize the section annotation by default and needs to be configured manually
@Aspect
public class SpringAOP {

     /**
     * Pointcut expression exercise
     * within:
     *  1.within(com.jt.*.DeptServiceImpl)   Class under first level package
     *  2.within(com.jt..*.DeptServiceImpl)  ..Represents a class under a multi-level package
     *  3.within(com.jt..*)  All classes under the package
     *
     * execution(Return value type package name Class name Method name (parameter list)
     *  1.execution(* com.jt..*.DeptServiceImpl.add*())
     *  Note: the return value type is arbitrary, com Class of DeptServiceImpl in all packages under JT
     *        And has no parameters
     *
     *  2.execution(* com.jt..*.*(..))
     *  Note: the return value type is arbitrary, com All methods and arbitrary parameters of all classes of all packages under JT package
     *
     *  3.execution(int com.jt..*.*(int))
     *  4.execution(Integer com.jt..*.*(Integer))
     *  Stress: there is no automatic disassembly and assembly function in Spring expression! Note the parameter type
     *
     * @annotation(Package name Annotation name)
     *     @Before("@annotation(com.jt.anno.Cache)")
     *    Block only the contents of specific annotations
     */

    //        Define pointcut expressions
    @Pointcut("@annotation(com.jt.vo.aop.Cath)")
    public void pointcut() {

    }

    //1. Define before notification
//    @Before("bean(userServiceImpl)")
    //@Before("within(com.jt..*)")
    //@Before("execution(* com.jt..*.userServiceImpl.add*())")
    @Before("pointcut()")
    public void before() {
        System.out.println("I am userServiceImpl Pre notification of");
    }

    @AfterReturning("pointcut()")
    public void AfterReturning() {
        System.out.println("I am userServiceImpl Pre notification of");
    }

    @AfterThrowing("pointcut()")
    public  void  afterThrowing(){
        System.out.println("I am userServiceImpl Exception notification,I won't come out without reporting an error");
    }

    @After("pointcut()")
    public  void  after(){
        System.out.println("I am userServiceImpl Post notification");
    }
//
//    @Around("pointcut()")
//    public  void  around(){
//        System.out.println("I'm userServiceImpl surround notification");
//    }

}


1.5.4 edit configuration class

package com.jt.vo;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.jt.vo")
@EnableAspectJAutoProxy(proxyTargetClass=false) //Start AOP annotation to create proxy object
//JDK dynamic agent is enabled by default,
//When the target object does not implement the interface, CGLIB is used
//Force cglib proxyTargetClass=true
//JDK agent creation is fast Running slightly slower
//CGLIB is slower to create and faster to run

public class SpringConfig {
}

1.5.5 writing test classes

package com.jt.vo.aop;

import com.jt.vo.SpringConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestUser {

    @Test
    public  void  testUserService(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService= (UserService) context.getBean(UserService.class);
        userService.addUser();
        userService.deleteUser();
    }
}

1.5.6 test results

1.6.1 @Before action

Note: the pre notification is executed before the target method is executed
Purpose: if you need to record the status of the program before method execution, you can use pre notification
Demand: 1 Gets the type of the target object
2. Get the name of the target method
3. Obtain the parameters of the target method

    /*Spring In order to obtain the data in the target object and method dynamically by AOP, the joinPoint object is used
     * Transfer data
     * getSignature : Method signature gets the parameters of the method
     * */

    /*Spring In order to obtain the data in the target object and method dynamically by AOP, the joinPoint object is used
     * Transfer data
     * getSignature : Method signature gets the parameters of the method
     * */
@Before("pointcut()")
public void before(JoinPoint joinPoint){
    System.out.println("Gets the type of the target object:"+joinPoint.getTarget().getClass());
    System.out.println("Gets the target object class name:"+joinPoint.getSignature().getDeclaringTypeName());
    System.out.println("Gets the target object method name:"+joinPoint.getSignature().getName());
    System.out.println("Get method parameters:"+ Arrays.toString(joinPoint.getArgs()));
    System.out.println("I am before notice");
}

Test results:

1.6.2 @AfterReturning

Description: after returning is executed after the target method is executed
Purpose: used to monitor the return value of methods and record logs

1). Add the test method String after (Integer id) to the interface

package com.jt.vo.aop;

public interface UserService {
//    Test methods in aop
    String after(Integer id);

2). Implement the target method, add an annotation class and hand it over to the AOP aspect

package com.jt.vo.aop;

import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Override
    @Cath
    public String after(Integer id) {
        return "spring Notification test" ;
    }
}

3). Edit AOP method test

package com.jt.vo.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

//1.AOP needs to be managed by Spring container
@Component
//2. Identify this class as AOP section
//  The Spring container does not recognize the section annotation by default and needs to be configured manually
@Aspect
public class SpringAOP {

    //        Define pointcut expressions
    @Pointcut("@annotation(com.jt.vo.aop.Cath)")
    public void pointcut() {

    }
@AfterReturning(pointcut = "pointcut()",returning = "result")
public void AfterReturning(JoinPoint joinPoint,Object result) {
    System.out.println("I am userServiceImpl Run notification for"+joinPoint.getArgs());
    System.out.println("Result of user return value"+result);
}

4) Edit test class

package com.jt.vo.aop;

import com.jt.vo.SpringConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestUser {

@Test
public  void  testUserService2(){
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    UserService userService= (UserService) context.getBean(UserService.class);
    userService.after(112);
}

5) Test results

1.6.3 @AfterThrowing

Function: after throwing can be used to record exceptions thrown when the target method is executed

1). Edit business interface

2). Edit business implementation class

3) Edit exception notification type

4) Edit test class

5) View results

1.6.4 @Around

1.6.4.1 @Around effect

Rule: execute before and after the target method is executed
Actual effect: it can control whether the target method is executed

1.6.4.2 surround notification learning

/**
 * Description of surround notification
 * Function: it can control whether the target method is executed
 * Parameter: proceed ingjoinpoint controls the execution of the target method through the processed method
 * matters needing attention:
 *      ProceedingJoinPoint is only supported for around advice
 * @return
 */
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint){
    Object result = null;
    try {
        System.out.println("Surround notification start");
        //1. Execute the next Notice 2 Implement target method 3 Receive return value
        Long start = System.currentTimeMillis();
        result = joinPoint.proceed();
        Long end = System.currentTimeMillis();
        System.out.println("time consuming:"+(end-start));
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    System.out.println("End of surround notification");
    return result;
}

1.7 explanation of knowledge points

1.7.1 pointcut

Note: whether the judgment method can enter the section IF judgment
Note: @ Pointcut internal edit Pointcut expression
Judgment basis:

1.7.2. Joinpoint

Note: when the user executes a method, if the method satisfies the pointcut expression, the method is the connection point
If you need to get method related parameters in the notification, Spring will encapsulate the joinPoint object Assign values to notification parameters

In popular understanding, the original method of execution is renamed and assigned Joinpoint() = addUser()

1.8 execution sequence of notification method

1. Execute around to start
2. Execute before
3. Implementation objectives and methods
4. Execute after returning
5. Execute afterThrowing
6. Execute after
7. The execution of the around notice ends

1.9 notes on Order

Description: study how to control the execution order of multiple sections
Method: through the Order annotation

Topics: Java Programming AOP