AOP concept and operation

Keywords: Java Spring

AOP concept

  • What is AOP?

    Aspect oriented programming, AOP can isolate all parts of business logic, so as to reduce the coupling between all parts of business logic, improve the reusability of programs, and improve the development efficiency.

    Generally speaking, it is to enhance the main functions without modifying the source code

  • AOP underlying principle

    The underlying AOP uses dynamic proxies

    • The first case: there are interfaces and JDK dynamic agent technology is used

      Create interface implementation class proxy object

    • The second case: without interface, CGLIB dynamic agent technology is used

      Creates a proxy object for a subclass of the current class

  • AOP underlying principle (JDK dynamic agent technology)

    Scenario simulation: we already have a UserDaoImpl class that implements the methods of the UserDao interface. Now we want to enhance these two methods without changing the source code

    public class UserDaoImpl implements UserDao {
        @Override
        public int add(int a, int b) {
            return a+b;
        }
    
        @Override
        public String update(String username) {
            return username;
        }
    }
    

    The first thing to use is the Proxy class. Call the Proxy.newProxyInstance method to create a Proxy object of the UserDao interface

    Looking at the Java 8 documentation, this method requires three parameters

    • First parameter: class loader
    • The second parameter: the interface of the implementation class
    • The third parameter is an interface object. We can use anonymous internal classes or create an implementation class of the interface. The methods in the implementation class are used to enhance the code
    public class MyProxy {
        public static void main(String[] args) {
            Class[] interfaces = {UserDao.class};
            UserDaoImpl userDao = new UserDaoImpl();
            UserDao dao = (UserDao) Proxy.newProxyInstance(MyProxy.class.getClassLoader(), interfaces, new UserProxy(userDao));
            int add = dao.add(10, 20);
            System.out.println("After enhancement, the results are:" + add);//60
        }
    }
    
    class UserProxy implements InvocationHandler {
    
        //The UserDao Object could have been written here. For the sake of generality, it is written out as an Object object
        private Object obj;
    
        public UserProxy(Object obj){
            this.obj = obj;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //Explain the parameters. Method represents the method name we call externally, and args represents the parameters in the method
            //Enhanced code before method execution
            System.out.println(method.getName() + "Before the method, the parameters are:" + Arrays.toString(args));
            //Enhanced method execution
            Object result = method.invoke(obj, args);
            //Enhanced code after method execution
            System.out.println("The result of the original method is:" + result);//30
    		//This code is only applicable to the add method. I want to test whether I can modify the return value
            int result1 = (int)result * 2;
            return result1;
        }
    }
    
  • AOP related terms

    • Join point: which methods in the class can be enhanced. These methods are called join points
    • Pointcuts: methods that are really enhanced are called pointcuts
    • Notification (enhancement): the logical part of the actual enhancement, called notification, has five notification types
      • Pre notification: executed before the enhanced method
      • Post notification: executed after the enhanced method
      • Surround notification: executed before and after the enhanced method
      • Exception notification: the enhanced method executes after throwing an exception
      • Final notice: final execution
    • Aspect: the process of applying notifications to pointcuts is called aspect
  • Some preparations for using AOP

    • Spring frameworks generally implement AOP operations based on AspectJ

      AspectJ is not a part of Spring. It is an independent AOP framework. Generally, AspectJ and Spring framework are used together for AOP operation

    • Implementation of AOP operation based on AspectJ

      • Implementation of configuration file based on xml
      • Annotation based implementation (use)
    • In addition to the related jar packages imported earlier, we also need to import AOP related dependencies

    • Pointcut expression

      Writing method: execution([permission modifier], [return type], [class full path], [method name] ([parameter list]))

      For example, enhance the add method under the com.yellowstar.dao.UserDao class

      The return value type can be ignored and not written. The parameter list is replaced by

      excution(* com.yellowstar.dao.UserDao.add(...))

  • AOP operations (annotation based implementation)

    1. Create an enhanced class and a proxy class for an enhanced class

      //Enhanced class
      public class User {
          //Enhanced method
          public void add(){
              System.out.println("user  add......");
          }
      }
      
      //Enhanced proxy class
      public class UserProxy {
          public void before(){
              System.out.println("before......");
          }
      }
      
    2. Configure the xml file and create two class objects using annotation

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
          <!--Scan annotation-->
          <context:component-scan base-package="com.yellowstar"></context:component-scan>
      </beans>
      
      //Enhanced class
      @Component
      public class User {
          //Enhanced method
          public void add(){
              System.out.println("user  add......");
          }
      }
      
      //Enhanced proxy class
      @Component
      public class UserProxy {
          public void before(){
              System.out.println("before......");
          }
      }
      
    3. Add the @ Aspect annotation for the enhanced class and configure the generation proxy object in the xml file

      //Enhanced proxy class
      @Component
      @Aspect
      public class UserProxy {
          public void before(){
              System.out.println("before......");
          }
      }
      
      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      
    4. Before enhancing the notification method of the class, set the corresponding notification annotation and use the pointcut expression

      //Enhanced proxy class
      @Component
      @Aspect
      public class UserProxy {
          //Before advice 
          @Before(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))")
          public void before() {
              System.out.println("before......");
          }
      
          //Final notice
          @After(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))")
          public void after() {
              System.out.println("after......");
          }
      
          //Post notification
          @AfterReturning(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))")
          public void afterReturning() {
              System.out.println("afterReturning......");
          }
      
          //Exception notification
          @AfterThrowing(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))")
          public void afterThrowing() {
              System.out.println("afterThrowing......");
          }
      
          //Around Advice 
          @Around(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))")
          public void around(ProceedingJoinPoint point) throws Throwable {
              System.out.println("add before around......");
              //The code on this statement is before the method is executed, and the following code is after the method is executed
              point.proceed();
              System.out.println("add after around......");
          }
      }
      
      Execution results:
      add before around......
      before......
      user  add......
      add after around......
      after......
      afterReturning......
      

      The above AOP operations have been completed. There are two more details about the above operations that can be optimized

    5. Extract the same pointcut

      We find that the entry points of these notices are the same, so we can extract them

      Create a method, configure the Pointcut annotation, configure the Pointcut expression, and call the method where the same Pointcut is required

      //Enhanced proxy class
      @Component
      @Aspect
      public class UserProxy {
          @Pointcut(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))")
          public void point(){}
      
          //Before advice 
          @Before(value = "point()")
          public void before() {
              System.out.println("before......");
          }
      }
      
    6. There are multiple enhancement methods. How to set the order of execution

      Use the annotation order (numeric value). The smaller the value, the higher the priority

      //Enhanced agent class 1
      @Component
      @Aspect
      @Order(3)
      public class UserProxy {
          @Pointcut(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))")
          public void point(){}
      
          //Before advice 
          @Before(value = "point()")
          public void before() {
              System.out.println("before......");
          }
      }
      
      //Enhanced agent class 2
      @Component
      @Aspect
      @Order(0)
      public class UserProxyMax {
          @Before(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))")
          public void before(){
              System.out.println("UserProxyMax before...");
          }
      }
      //Set the order of the two enhanced proxy classes as above, and the enhanced method in UserProxyMax will be executed first
      
  • AOP operation (based on xml configuration file)

  1. Create an enhanced class and an enhanced class

    //Enhanced class
    public class Book {
        public void buy(){
            System.out.println("book buy...");
        }
    }
    //Enhancement class
    public class BookProxy {
        public void before(){
            System.out.println("BookProxy before...");
        }
    }
    
    
  2. Configure the following in the xml file

        <!--Create objects of two classes-->
    	<bean id="book" class="com.yellowstar.spring5.AopXml.Book"></bean>
        <bean id="bookProxy" class="com.yellowstar.spring5.AopXml.BookProxy"></bean>
    
        <!--to configure AOP Enhancement point-->
        <aop:config>
            <!--Configure pointcuts-->
            <aop:pointcut id="p" expression="execution(* com.yellowstar.spring5.AopXml.Book.buy(..))"/>
            <!--Configure section-->
            <aop:aspect ref="bookProxy">
                <!--Configuration method-->
                <aop:before method="before" pointcut-ref="p"></aop:before>
            </aop:aspect>
        </aop:config>
    

Posted by bob on Tue, 28 Sep 2021 21:04:30 -0700