AOP in-depth understanding and Bean loading process

Keywords: Java Spring Spring Boot

Spring series courses - AOP programming

Chapter one: static agent design pattern

1. Why do you need agent design pattern
1.1 problems
  • In Java EE layered development, which layer is the most important for us

    DAO ---> Service --> Controller 
    
    JavaEE In layered development, the most important thing is Service layer
    
  • What code is included in the Service layer?

    Service In layer = Core functions(Dozens of lines and hundreds of codes) + Additional features(Additional functions)
    1. Core functions
       Business operation
       DAO call
    2. Additional features 
       1. Not a business
       2. not essential
       3. The amount of code is very small 
       
       Transactions, logs, performance...
       
    
  • How about writing additional functions in the Service layer?

    Service The angle of the caller of the layer( Controller):Need in Service Additional functions for layer writing.
                             Software designer: Service Layer does not require additional functionality
                             
    
  • Solutions in real life

2. Agent design mode
1.1 concept
Add additional functionality to the original class (target) through the proxy class
 Benefits: benefits to primitive classes(target)Maintenance of
1.2 interpretation of terms
1. Target class original class 
   It refers to business class (Core functions --> Business operation DAO call)
2. Target method
   Target class(Primitive class)The method in is the target method(Original method)
3. Additional features (Additional functions)
   Log, transaction, performance
1.3 core elements of agent development
proxy class = Target class(Primitive class) + Additional features + Primitive class(Target class)Implement the same interface

landlord or landlady ---> public interface UserService{
               m1
               m2
          }
          UserServiceImpl implements UserService{
               m1 ---> Business operation DAO call
               m2 
          }
          UserServiceProxy implements UserService
               m1
               m2
1.4 coding

Static proxy: manually write a proxy class (. Java. Class) for each original class

1.5 problems of static agent
1. There are too many static files, which is not conducive to project management
   UserServiceImpl  UserServiceProxy
   OrderServiceImpl OrderServiceProxy
2. Poor maintenance of additional functions
   The modification of additional functions in the proxy class is complex(trouble)

The second chapter is the dynamic agent development of Spring

1. The concept of spring dynamic proxy
Concept: the proxy class is the original class(Target class)Add additional features
 Benefits: benefits to primitive classes(Target class)Maintenance of
2. Build a development environment
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.1.14.RELEASE</version>
</dependency>

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.8.8</version>
</dependency>

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.3</version>
</dependency>

3. Development steps of spring dynamic agent
  1. Create original object (target object)

    public class UserServiceImpl implements UserService {
        @Override
        public void register(User user) {
            System.out.println("UserServiceImpl.register Business operation + DAO ");
        }
    
        @Override
        public boolean login(String name, String password) {
            System.out.println("UserServiceImpl.login");
            return true;
        }
    }
    
    
    <bean id="userService" class="com.baizhiedu.proxy.UserServiceImpl"/>
    
  2. Additional features
    MethodBeforeAdvice interface

    Additional functions are written in the implementation of the interface and run before the original method is executed.
    
    public class Before implements MethodBeforeAdvice {
        /*
          Function: you need to write the additional functions that run before the execution of the original method in the before method
         */
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("-----method before advice log------");
        }
    }
    
    <bean id="before" class="com.baizhiedu.dynamic.Before"/>
    
  3. Define pointcuts

    Entry point: where additional functions are added
    
    Purpose: the programmer decides to add additional functions to the original method according to his own needs
    register
    login
    
    Simple test: all methods are used as entry points and add additional functions.
    
    <aop:config>
       <aop:pointcut id="pc" expression="execution(* *(..))"/>
    </aop:config>
    
  4. Assembly (2 3 integration)

    Meaning of expression: all methods are added before Additional features of
    <aop:advisor advice-ref="before" pointcut-ref="pc"/>
    
  5. call

    Objective: to obtain Spring The dynamic proxy object created by the factory and called
    ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
    be careful:
       1. Spring The factory passes through the original object id Value gets the proxy object
       2. After obtaining the proxy object, you can store the object by declaring the interface type
       
    UserService userService=(UserService)ctx.getBean("userService");
    
    userService.login("")
    userService.register()
    
    
4. Dynamic agent detail analysis
  1. Where is the dynamic proxy class created by Spring?

    Spring At runtime, the framework uses dynamic bytecode technology to JVM Created, running in JVM Internally, after the procedure is completed, it will communicate with JVM Disappear together
    
    What is dynamic bytecode technology:Through the third dynamic bytecode framework, in JVM Create the bytecode of the corresponding class, and then create the object. When the virtual machine ends, the dynamic bytecode disappears.
    
    Conclusion: dynamic agents do not need to define class files, they are JVM It is created dynamically during operation, so it will not cause too many static agents and class files, which will affect project management.
    

    1. Dynamic agent programming simplifies agent development

      When creating proxy objects of other target classes (original classes) without changing the additional functions, you only need to specify the original class(target)Object.
      
    2. The maintainability of additional functions of dynamic agent is greatly enhanced

Chapter 3: detailed explanation of Spring dynamic proxy

1. Detailed explanation of additional functions
  • MethodBeforeAdvice analysis

    1. MethodBeforeAdvice Interface function: additional function operation is performed before the original method is executed.
    
    public class Before1 implements MethodBeforeAdvice {
        /*
          Function: you need to write the additional functions that run before the execution of the original method in the before method
    
          Method: The original method to which the extra functionality is added
                  login method
    
                  register method
    
                  showOrder method
    
          Object[]: The parameter of the original method added by the additional function. String name,String password
                                                   User
    
           Object: The original object UserServiceImpl added by the additional function
                                              OrderServiceImpl
         */
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("-----new method before advice log------");
        }
    }
    
    2. before How to use the three parameters of the method in practice.
       before In practice, the parameters of the method will be used as needed. They may not be used or may not be used at all.
    
       Servlet{
           service(HttpRequest request,HttpResponse response){
                request.getParameter("name") -->
                
                response.getWriter() ---> 
           
           }
       
       }
    
    
  • Methodinterceptor (method interceptor)

    methodinterceptor Interface: additional functions can be run before, after and before the execution of the original method as required.
    
    public class Arround implements MethodInterceptor {
        /*
             invoke Function of the method: additional functions are written in invoke
                            Before the original method of additional functions
                                     After the original method
                                     Before and after the original method execution
             Determine: how does the original method work
    
             Parameter: method invocation (Method): the original method added by the additional function
                        login
                        register
                  invocation.proceed() ---> login function
                                            register function
    
              Return value: Object: the return value of the original method
    
             Date convert(String name)
         */
    
    
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
              System.out.println("-----Additional features log----");
              Object ret = invocation.proceed();
    
              return ret;
        }
    }
    
    
    

    Additional functionality runs after the original method is executed

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
      Object ret = invocation.proceed();
      System.out.println("-----Additional functionality runs after the original method is executed----");
    
      return ret;
    }
    

    Additional functionality runs before and after the original method is executed

    What additional functions are added before and after the execution of the original method?
    affair
    
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
      System.out.println("-----Additional functionality runs before the original method is executed----");
      Object ret = invocation.proceed();
      System.out.println("-----Additional functionality runs after the original method is executed----");
    
      return ret;
    }
    

    Additional functionality runs when the original method throws an exception

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
    
      Object ret = null;
      try {
        ret = invocation.proceed();
      } catch (Throwable throwable) {
    
        System.out.println("-----The original method throws an exception to perform additional functions ---- ");
        throwable.printStackTrace();
      }
    
    
      return ret;
    }
    

    MethodInterceptor affects the return value of the original method

    The return value of the original method, directly as invoke Method, MethodInterceptor Does not affect the return value of the original method
    
    MethodInterceptor Affects the return value of the original method
    Invoke Method instead of directly returning the running result of the original method.
    
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
       System.out.println("------log-----");
       Object ret = invocation.proceed();
       return false;
    }
    
2. Detailed explanation of entry point
The entry point determines where additional functions are added(method)

<aop:pointcut id="pc" expression="execution(* *(..))"/>
exection(* *(..)) ---> All methods are matched    a  b  c 

1. execution()  Pointcut function
2. * *(..)      Pointcut expression 
2.1 pointcut expression
  1. Method pointcut expression

    *  *(..)  --> All methods
    
    * ---> Modifier return value
    * ---> Method name
    ()---> Parameter table
    ..---> No requirements for parameters (Whether there are parameters or not, any number of parameters and any type of parameters are OK)
    
    • Define the login method as the entry point

      * login(..)
      
      # Define register as the entry point
      * register(..)
      
    • The login method is defined, and the login method has two string type parameters as the entry point

      * login(String,String)
      
      #Note: for types not in java.lang package, the fully qualified name must be written
      * register(com.baizhiedu.proxy.User)
      
      # .. Can be used with specific parameter types
      * login(String,..)  --> login(String),login(String,String),login(String,com.baizhiedu.proxy.User)
      
    • Precise method entry point limitation

      Modifier return value         package.class.method(parameter)
      
          *               com.baizhiedu.proxy.UserServiceImpl.login(..)
          *               com.baizhiedu.proxy.UserServiceImpl.login(String,String)
      
  2. Class pointcut

    Specify a specific class as the pointcut(Where additional features are added),Naturally, all methods in this class will add corresponding additional functions
    
    • Grammar 1

      #All methods in the class add additional functionality 
      * com.baizhiedu.proxy.UserServiceImpl.*(..)  
      
    • Grammar 2

      #Ignore package
      1. Class has only one level package  com.UserServiceImpl
      * *.UserServiceImpl.*(..)
      
      2. Class has multi-level packages    com.baizhiedu.proxy.UserServiceImpl
      * *..UserServiceImpl.*(..)
      
  3. Package pointcut expression practice

    Specify where the package is added as additional functions. All classes and methods in the natural package will add additional functions
    
    • Grammar 1

      #All classes in the pointcut package must be in the proxy, not in the sub package of the proxy package
      * com.baizhiedu.proxy.*.*(..)
      
    • Grammar 2

      #The pointcut is in effect for both the current package and its sub packages 
      * com.baizhiedu.proxy..*.*(..) 
      
2.2 pointcut function
Pointcut function: used to execute pointcut expressions
  1. execution

    The most important pointcut function has the most complete functions.
    Execution method pointcut expression class pointcut expression package pointcut expression 
    
    Disadvantages: execution Execute the pointcut expression, which is troublesome to write
         execution(* com.baizhiedu.proxy..*.*(..))
         
    Note: other pointcut function simplifications are execution The writing complexity is completely consistent in function
    
  2. args

    Function: mainly used for functions(method) Parameter matching
    
    Pointcut: method parameter must be a parameter of type 2 strings
    
    execution(* *(String,String))
    
    args(String,String)
    
  3. within

    Function: it is mainly used for matching class and package pointcut expressions
    
    Entry point: UserServiceImpl This class
    
    execution(* *..UserServiceImpl.*(..))
    
    within(*..UserServiceImpl)
    
    execution(* com.baizhiedu.proxy..*.*(..))
    
    within(com.baizhiedu.proxy..*)
    
    

4.@annotation

Function: add additional functions for methods with special annotations

<aop:pointcut id="" expression="@annotation(com.baizhiedu.Log)"/>
  1. Logical operation of pointcut function

    It refers to integrating multiple pointcut functions to work together to complete more complex requirements
    
    • and operation

      Case: login Two strings of parameters at the same time 
      
      1. execution(* login(String,String))
      
      2. execution(* login(..)) and args(String,String)
      
      Note: unlike operations, it is used for pointcut functions of the same type 
      
      Case: register Methods and login Method as a starting point 
      
      execution(* login(..)) or  execution(* register(..))
      
      
    • or operation

      Case: register Methods and login Method as a starting point 
      
      execution(* login(..)) or  execution(* register(..))
      

Chapter 4: AOP programming

1. AOP concept
AOP (Aspect Oriented Programing)   Aspect oriented programming = Spring Dynamic agent development
 The program development with aspect as the basic unit completes the construction of the program by coordinating and calling each other
 section = breakthrough point + Additional features

OOP (Object Oritened Programing)   object-oriented programming Java
 The program development with object as the basic unit completes the construction of the program through the cooperation and call between objects

POP (Producer Oriented Programing) Process oriented(Methods and functions)programming C 
The program development with process as the basic unit completes the construction of the program through the cooperation and call between processes
AOP Concept of:
     The essence is Spring Get dynamic agent development, and add additional functions to the original class through the agent class.
     Benefits: it is conducive to the maintenance of the original class

be careful: AOP Programming cannot replace OOP,OOP Programming is intentionally supplemented.
2. Development steps of AOP programming
1. Original object
2. Additional features (MethodInterceptor)
3. breakthrough point
4. Assembly section (Additional features+breakthrough point)
3. Definition of terms
section = breakthrough point + Additional features 

geometry
   noodles = spot + Same nature

The fifth chapter is the underlying implementation principle of AOP

1. Core issues
1. AOP How to create a dynamic proxy class(Dynamic bytecode Technology)
2. Spring How does a factory create a proxy object
   Through the of the original object id Value to get the proxy object
2. Creation of dynamic proxy class
2.1 dynamic agent of JDK
  • Detailed explanation of Proxy.newProxyInstance method parameters

  • code

    public class TestJDKProxy {
    
        /*
            1. Borrow class loader TestJDKProxy
                           UserServiceImpl
            2. JDK8.x front
    
                final UserService userService = new UserServiceImpl();
         */
        public static void main(String[] args) {
            //1 create original object
            UserService userService = new UserServiceImpl();
    
            //2. Create dynamic agent with JDK
            /*
    
             */
    
            InvocationHandler handler = new InvocationHandler(){
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("------proxy  log --------");
                    //Original method run
                    Object ret = method.invoke(userService, args);
                    return ret;
                }
            };
    
            UserService userServiceProxy = (UserService)Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(),userService.getClass().getInterfaces(),handler);
    
            userServiceProxy.login("suns", "123456");
            userServiceProxy.register(new User());
        }
    }
    
    
2.2 dynamic agent of cglib
CGlib The principle of creating a dynamic proxy: the parent-child inheritance relationship creates a proxy object, with the original class as the parent class and the proxy class as the child class. This can not only ensure the consistency of the two methods, but also provide a new implementation in the proxy class(Additional features+Original method)

  • CGlib encoding

    package com.baizhiedu.cglib;
    
    import com.baizhiedu.proxy.User;
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class TestCglib {
        public static void main(String[] args) {
            //1 create original object
            UserService userService = new UserService();
    
            /*
              2 Creating dynamic proxy objects by cglib
                Proxy.newProxyInstance(classloader,interface,invocationhandler)
    
                Enhancer.setClassLoader()
                Enhancer.setSuperClass()
                Enhancer.setCallback();  ---> MethodInterceptor(cglib)
                Enhancer.create() ---> agent
             */
    
            Enhancer enhancer = new Enhancer();
    
            enhancer.setClassLoader(TestCglib.class.getClassLoader());
            enhancer.setSuperclass(userService.getClass());
    
    
            MethodInterceptor interceptor = new MethodInterceptor() {
                //Equivalent to InvocationHandler --- invoke
                @Override
                public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    System.out.println("---cglib log----");
                    Object ret = method.invoke(userService, args);
    
                    return ret;
                }
            };
    
            enhancer.setCallback(interceptor);
    
            UserService userServiceProxy = (UserService) enhancer.create();
    
            userServiceProxy.login("suns", "123345");
            userServiceProxy.register(new User());
        }
    }
    
    
  • summary

    1. JDK Dynamic agent   Proxy.newProxyInstance()  Create the implementation class of the proxy through the interface 
    2. Cglib Dynamic agent Enhancer                  Proxy class created by inheriting the parent class 
    
3. How does spring factory process original objects
  • Train of thought analysis

  • code

    public class ProxyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        @Override
        /*
             Proxy.newProxyInstance();
         */
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
            InvocationHandler handler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("----- new Log-----");
                    Object ret = method.invoke(bean, args);
    
                    return ret;
                }
            };
          return Proxy.newProxyInstance(ProxyBeanPostProcessor.class.getClassLoader(),bean.getClass().getInterfaces(),handler);
        }
    }
    
    <bean id="userService" class="com.baizhiedu.factory.UserServiceImpl"/>
    
    
    <!--1. realization BeanPostProcessor Processing
            2. Pair in configuration file BeanPostProcessor Configure
        -->
    
    <bean id="proxyBeanPostProcessor" class="com.baizhiedu.factory.ProxyBeanPostProcessor"/>
    
    

Chapter 6: annotation based AOP programming

1. Development steps of annotation based AOP programming
  1. Original object

  2. Additional features

  3. breakthrough point

  4. Assembly section

    # Additional functions @ Around are defined through the facet class
               Pointcuts are defined   @Around("execution(* login(..))")
               @Aspect Section class 
               
    package com.baizhiedu.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    
    /*
           1. Additional features
                     public class MyArround implements MethodInterceptor{
    
                          public Object invoke(MethodInvocation invocation){
    
                                  Object ret = invocation.proceed();
    
                                  return ret;
    
                          }
    
                     }
    
           2. breakthrough point
                 <aop:config
                     <aop:pointcut id=""  expression="execution(* login(..))"/>
     */
    @Aspect
    public class MyAspect {
    
        @Around("execution(* login(..))")
        public Object arround(ProceedingJoinPoint joinPoint) throws Throwable {
    
            System.out.println("----aspect log ------");
    
            Object ret = joinPoint.proceed();
    
    
            return ret;
        }
    }
       
    
     <bean id="userService" class="com.baizhiedu.aspect.UserServiceImpl"/>
    
        <!--
           section
             1. Additional features
             2. breakthrough point
             3. Assembly section
    
    
        -->
    <bean id="arround" class="com.baizhiedu.aspect.MyAspect"/>
    
    <!--inform Spring Annotation based AOP programming-->
    <aop:aspectj-autoproxy />
    
2. Details
  1. Pointcut reuse

    Pointcut reuse: define a function in the facet class@Pointcut Annotation defines pointcut expressions in this way, which is more conducive to pointcut reuse in the future.
    
    @Aspect
    public class MyAspect {
        @Pointcut("execution(* login(..))")
        public void myPointcut(){}
    
        @Around(value="myPointcut()")
        public Object arround(ProceedingJoinPoint joinPoint) throws Throwable {
    
            System.out.println("----aspect log ------");
    
            Object ret = joinPoint.proceed();
    
    
            return ret;
        }
    
    
        @Around(value="myPointcut()")
        public Object arround1(ProceedingJoinPoint joinPoint) throws Throwable {
    
            System.out.println("----aspect tx ------");
    
            Object ret = joinPoint.proceed();
    
    
            return ret;
        }
    
    }
    
  2. How dynamic agents are created

AOP The bottom layer implements two proxy creation methods
1.  JDK  Create a proxy object by creating a new implementation class through the implementation interface
2.  Cglib Make new subclasses by inheriting the parent class      Create proxy object

Default AOP Programming underlying applications JDK Dynamic proxy creation method 
If switching Cglib
     1. Annotation based AOP development
        <aop:aspectj-autoproxy proxy-target-class="true" />
     2. conventional AOP development
        <aop:config proxy-target-class="true">
        </aop>

Chapter 7, a pit in AOP development

Pit: in the same business class, there are only the outermost methods for mutual calls between business methods,Is the addition of additional features(The internal methods are called in an ordinary way. They all call the original method). If you want the inner method to call the method of the proxy object, you must AppicationContextAware Get the factory, and then get the proxy object.
public class UserServiceImpl implements UserService, ApplicationContextAware {
    private ApplicationContext ctx;


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
              this.ctx = applicationContext;
    }

    @Log
    @Override
    public void register(User user) {
        System.out.println("UserServiceImpl.register Business operation + DAO ");
        //throw new RuntimeException("test exception");

        //The login method -- > core function of the original object is called
        /*
            Design purpose: login method of proxy object -- > additional functions + core functions
            ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext2.xml");
            UserService userService = (UserService) ctx.getBean("userService");
            userService.login();

            Spring Factory heavyweight resources should create only one factory in an application
         */

        UserService userService = (UserService) ctx.getBean("userService");
        userService.login("suns", "123456");
    }

    @Override
    public boolean login(String name, String password) {
        System.out.println("UserServiceImpl.login");
        return true;
    }
}

Chapter VIII summary of AOP stage knowledge

Class loading process:

Load (load the class file into the memory and instantiate an object of java.lang.Class class in the Java heap memory), verify (ensure that the class file meets the requirements of the virtual machine), prepare (allocate memory for the class variable and set the initial value of the variable in the class. If it is final type, a constant will be generated as the value of this variable during compilation, and then assign this constant to the final variable in the preparation stage) Parsing (replacing the symbolic references in the constant pool with direct references), initialization (initializing class variables and other resources according to the subjective plan of the program. The initialization phase is the process of executing the class constructor () method. It is the automatic generation of the Javac compiler), use and uninstall. The three parts of verification, preparation and parsing are collectively referred to as connection.
.

Class loader:

3 types: startup classloader (% JRE home% / LIB), extension classloader (% JRE home% / lib / ext), application classpath (classpath)

Parental delegation model:

If a class loader receives a class loading request, it will not try to load the class itself, but delegate the request to the parent class loader to complete it. This is true for class loaders at each level. Therefore, all loading requests should eventually be transmitted to the top-level startup class loader, only
When the parent loader reports that it cannot complete the load request (it does not find the required class in its search scope), the child loader will try to complete the load by itself

Posted by ericw on Wed, 22 Sep 2021 10:50:32 -0700