Spring AOP Part 1 - initial spring AOP

catalogue

preface

Several concepts of AOP

Code example

Several common scenarios for notification

About @ Pointcut

summary

preface

        The previous article talked about dynamic agents and interceptor chains, Spring - dynamic proxy and interceptor . Because dynamic proxy is the foundation of spring AOP, you can read the previous article first to better understand this article. We can enhance the function of the proxy object through dynamic proxy. Spring AOP is also used to enhance the proxy object, but it makes the enhancement of the proxy object easier and more conducive to development and use.

Several concepts of AOP

        I'll first get the explanation of Spring's official website, and then try to explain it with my understanding.

                AOP official documents

        

  • Advice

         In fact, it is the function we need to enhance. For example, the method marked with @ Before, @ After and other annotations is a notification, which defines some behaviors to be performed at the pointcut, that is, how we want to enhance.

  • Join point

        Connection points are places where the program allows notification enhancements, such as before, after, or when an exception occurs. Spring AOP only supports method join points, that is, it can only be enhanced with the dimension of methods. Unlike other frameworks, it can also be enhanced when constructors or attribute assignments.

  • Pointcut

        Connection point is a conceptual thing. For example, the concept of connection point tells you that Spring AOP can be enhanced in the dimension of method. But what you can do is not necessarily what you will do. Because it is impossible to enhance all methods, and the tangent point is to specify the specific connection point, that is, which method to enhance.

  • Aspect

         In Spring AOP, if a class is annotated with the @ aspect annotation, it is an aspect. In fact, if you want to understand the aspect well, you must first understand the pointcut and notification. The aspect is the combination of pointcut and notification. In fact, if you read the last article, you should realize that it is very similar to the Advisor in Spring AOP,   However, the Advisor only contains one pointcut and notification, and many pointcuts and notifications can be defined in the aspect. However, in the end, Spring will parse them into advisors. In fact, it is like a conceptual thing. For example, a company can't work itself, but the employees in the company are working. Aspect is responsible for management. What really does is the pointcut and notification it contains.

  • Introduction

        Introduction is to introduce other interfaces into the existing interfaces to enhance the functions of the current interface

  • target

        That is, the proxied object, which needs to be enhanced

  • proxy

        When the target object is proxied, it becomes a proxy object. I believe the students who read the last article can understand

  • Weaving  

        Weaving can be understood as the process of applying the aspect to the target object to create a proxy. Some frameworks are woven at compile time, that is, modifying the source code directly near the code of the proxy object. Some frameworks are woven at run time, such as the proxy dynamic proxy method of Spring AOP, which will not change the code of the proxy object.

Code example

  • Introduce required dependencies
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.6</version>
            </dependency>
  • Test interfaces and implementation classes
    public interface IOrder {
    
        Integer query(String type);
    }
    
    @Service
    public class OrderService implements IOrder {
    
        @Override
        public Integer query(String type) throws Exception {
            System.out.println("Query type is" + type +  "Order quantity");
            //An error occurred during the simulation query
            try {
                //int a = 1 / 0;
            } catch (Exception ex) {
                throw new Exception("I was wrong");
            }
    
            return 1;
        }
    
    }
    
  • Add facet class
    @Aspect
    public class QueryAspect {
        @Pointcut("execution(* com.proxy.IOrder.query(..))")
        public void pointCut(){};
    
        @Before(value = "pointCut()")
        public void methodBefore(JoinPoint joinPoint) throws Exception {
            System.out.println("Before calling the target method @Before Parameter information can be obtained in advance:" + Arrays.toString(joinPoint.getArgs()));
            //Error simulating before
            //int a = 1 / 0;
        }
    
        @After(value = "pointCut()")
        public void methodAfter(JoinPoint joinPoint) {
            System.out.println("After calling the target method @After");
            // Simulate After exception
            int a = 1 / 0;
        }
    
        @AfterReturning(value = "pointCut()", returning = "result")
        public void methodAfterReturning(JoinPoint joinPoint, Object result) {
            System.out.println("After the target method returns @AfterReturning, The returned result can be obtained at this time " + result);
            //Error simulating AfterReturning
            //int a = 1 / 0;
        }
    
        @AfterThrowing(value = "pointCut()", throwing = "ex")
        public void methodAfterThrowing(JoinPoint joinPoint, Exception ex) {
            System.out.println("After throwing an exception, @AfterThrowing " + ex);
        }
    
        //@Around(value = "pointCut()")
        public Object methodAround(ProceedingJoinPoint pdj) {
            Object result = null;
            System.out.println("Before calling the target method @Around ");
            try {
                //Call target method
                result = pdj.proceed();
            } catch (Throwable ex) {
                System.out.println("Exception information captured:" + ex);
            }
            System.out.println("After calling the target method @Around ");
            return result;
        }
    }
  • Add configuration class and configure aspect bean
    @Configuration
    @EnableAspectJAutoProxy
    @ComponentScan(value = {"com.proxy"})
    public class AopConfig {
        @Bean
        public QueryAspect queryAspect() {
            return new QueryAspect();
        }
    }
    
  • Writing test classes
    public class ProxyMain {
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
            IOrder proxy = (IOrder) applicationContext.getBeanFactory().getBean("orderService");
            try {
                Object result = proxy.query("Erke");
                System.out.println("The query result is:" + result);
            } catch (Exception e) {
                System.out.println("Test class caught error:" + e);
            }
        }
    }
  • Comment out the @ Around notification first and view the running results
  • 1:When there are no exceptions
        Before calling the target method @Before Parameter information can be obtained in advance:[Erke]
        Execute the target method. The query type is hongxingerke order quantity
        After the target method returns @AfterReturning, At this time, you can get the returned result 1
        After calling the target method @After
        The query result is:1
    
    2:When the target method is abnormal
        Before calling the target method @Before Parameter information can be obtained in advance:[Erke]
        Execute the target method. The query type is hongxingerke order quantity
        After throwing an exception, @AfterThrowing java.lang.Exception: I was wrong
        After calling the target method @After
        Test class caught error: java.lang.Exception: I was wrong
        
        It can be seen that when the target method is abnormal,@AfterReturning Your notice will not be executed, but @After Your notice will continue    Continued implementation
    
    3: When @Before When notifying exceptions
        Before calling the target method @Before Parameter information can be obtained in advance:[Erke]
        Test class caught error: java.lang.ArithmeticException: / by zero
        
        so@AfterThrowing No capture @Before Notified exception,@After and @AfterReturning None of the notifications were executed
    
    4: When @AfterReturning When notifying exceptions
        Before calling the target method @Before Parameter information can be obtained in advance:[Erke]
        Execute the target method. The query type is hongxingerke order quantity
        After the target method returns @AfterReturning, At this time, you can get the returned result 1
        After calling the target method @After
        Test class caught error: java.lang.ArithmeticException: / by zero
    
        so@AfterThrowing No capture @AfterReturning Notified exception, and @After The notification will continue
    
    5: When @After When notifying exceptions
        Before calling the target method @Before Parameter information can be obtained in advance:[Erke]
        Execute the target method. The query type is hongxingerke order quantity
        After the target method returns @AfterReturning, At this time, you can get the returned result 1
        After calling the target method @After
        Test class caught error: java.lang.ArithmeticException: / by zero
        
        It can be seen that all three notifications will be executed
    
  • From the above execution results, we can find that
  1. @AfterThrowing can only catch exceptions at the tangent point.
  2. @The Before notification must be executed, and if there are exceptions in the execution process, the following steps will not be carried out.
  3. @The After notification is executed After the @ AfterReturning notification, and if the pointcut method throws an exception, the @ AfterReturning notification will not be executed.
  • The execution process of these three notifications is roughly as follows
    // @Before notification execution first
    try {
        try {
            //@Before notifies that if there are no exceptions, the target method will be executed at this time
        } catch (Throwable throwable) {
            //An exception occurred in the target method. The @ AfterThrowing notification will be executed at this time
            throw throwable;
        }
        //If the target method does not run out of exception, execute the notification of @ AfterReturn at this time
    } catch (Exception exception) {
                    
    } finally {
        //The @ After notification will be executed as long as @ Before does not throw an exception
    }
  • You must know how to use the above three notifications. What about @ Around notifications? We will comment out the other three notifications and only keep the @ Around notification to observe the execution results
    @Around(value = "pointCut()")
        public Object methodAround(ProceedingJoinPoint pdj) {
            Object result = null;
            System.out.println("Before calling the target method @Around ");
            try {
                //Call target method
                result = pdj.proceed();
            } catch (Throwable ex) {
                System.out.println("Exception information captured:" + ex);
            }
            System.out.println("After calling the target method @Around ");
            return result;
        }
  • results of enforcement

    1:When the pointcut method has no exceptions
        Before calling the target method @Around 
        Execute the target method. The query type is hongxingerke order quantity
        After calling the target method @Around 
        The query result is:1
    
    2: When the pointcut method is abnormal
        Before calling the target method @Around 
        Execute the target method. The query type is hongxingerke order quantity
        Exception information captured: java.lang.Exception: I was wrong
        After calling the target method @Around 
        The query result is:null
  •   It can be seen that the function of @ Around notification is more powerful than the other three. It cuts the pointcut method into the notification and can be enhanced in various places of the pointcut method. It can be said that it has all the functions of the above three notifications. The above three notifications perform their respective functions and can only complete one enhancement. So If the enhanced requirement is simple, it only needs to be enhanced at a certain point. Then select the notice above. Its advantage is simple and efficient. If the functions to be enhanced are complex and need to be enhanced at multiple connection points, you need to use @ Around. Its advantage lies in its strong functionality.  

Several common scenarios for notification

  • @Before notification can obtain the parameter information of the target method in advance, so it can be used as permission authentication (some parameters can go down, and some can stop here). It can also be used to save the interface access record (because this notification will be executed, and other exceptions may not save the access record)
  • @After returning notification can obtain the execution result of the target method, so it can enhance the obtained result, such as adding some information to the result or deleting some information. You can also save a copy of the results of the target method or send a copy to other systems. Mainly to enhance the results.
  • @After notification, because the notification will be executed regardless of whether the target method fails or not, it can be used to perform some operations to close resources.
  • @The AfterThrowing notification is mainly used to handle exceptions, such as data backup and restore
  • @The Around notification is mainly used when complex enhancements are required.

About @ Pointcut

        In fact, we should already know from the above that it defines a tangent point, as in the above example

@Pointcut("execution(* com.proxy.IOrder.query(..))")
public void pointCut(){};

        The @ Pointcut specifies the Pointcut method. The pointCut() method is a signature. The signature is only used to simplify the use of the Pointcut without writing it over and over again   execution(* com.proxy.IOrder.query(..))  

        @ In addition to execution, there are other options in Pointcut, such as within, target, args, annotation, etc. execution is the label of the most commonly used matching method. This article only introduces this one.

         The syntax of exception() is as follows:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
  • Modifier pattern: modifier representing method, such as public, private, etc.
  • RET type pattern: indicates the return value type of the method, * indicates the return value of any type
  • Declaring type pattern: indicates the path of the class where the method is located.
  • Name pattern: represents the method name. You can use the full method name or query * to match all methods starting with query
  • Param pattern: indicates the parameter type. Multiple parameter types can be specified, separated by commas, or * can be used to match parameters of any type. For example, (int, *) indicates that the first parameter type is int and the second is a method of any type. You can also use (..) to match the parameters of zero or more arbitrary methods.
  • Throws pattern: indicates the exception thrown by the method

        You can also use & & (and), | (or)( (non expression)  

  1.  @ Pointcut("execution(Integer   com.proxy.IOrder.query(..) "): represents a query method matching integer type, but the parameters of the method are not limited.
  2. @Pointcut("execution(*   com.proxy.IOrder.query(int)) "): indicates that the query method matches any type, but there can only be one parameter of type int in the parameter list.
  3. @Pointcut ("execution (integer com. Proxy. Iorder. Query (String)) 𞓜 execution (integer com. Proxy. Iorder. Query (int))"): indicates the query method with matching parameter type of String or int

summary

        This paper introduces some concepts of AOP, introduces the way Spring AOP defines aspects, pointcuts and notifications with examples, and also introduces the use scenarios of different notifications. As an introduction to Spring AOP, this article mainly focuses on code use. It aims to know how to use Spring AOP after reading this article. If you still don't know how to use it or encounter any problems in the process of using it, you can point it out in the comment area and I will reply and discuss with you in time, because your problem may also be my problem. I will reply in time. Subsequent articles will start with the source code and discuss it   How Spring implements enhancements in different aspects.

Keywords: Java Spring Dynamic Proxy

Added by rolwong on Tue, 07 Sep 2021 07:55:15 +0300