Handwritten Spring framework---AOP implementation

Table of contents

Containers are an advanced tool for OOP

system requirement

Separation of concerns Concern Separation

original implementation

Member of AOP

Types of Advice

Execution order of a single Aspect

Execution order of multiple Aspects

Introduction-Introduction Advice

Proxy mode

JDK dynamic proxy

JDK dynamic proxy of the realization principle of Spring AOP

CGLIB dynamic proxy of the implementation principle of Spring AOP

JDK dynamic proxy and CGLIB

Self-developed framework AOP mechanism 1.0

The AOP 1.0 of the self-developed framework needs to be improved

AspectJ framework

Self-developed framework AOP2.0


  • Containers are an advanced tool for OOP

  • Open up the development channel from top to bottom in a low-coupling and low-invasive way
    • Fill in the code logic step by step to realize business functions, and each layer of logic can be seamlessly replaced
    • OOP decomposes business programs into objects at various levels, and completes business through object linkage
    • Unable to handle general system requirements scattered in various businesses well
  • system requirement

  • Only code farmers care about the needs
    • Add log information: add statistical time for each method
    • Add system permission check: limit for some methods
    • Under OOP, common logic work must be added to each method, which increases maintenance costs
  • Separation of concerns Concern Separation

  • Different problems are handed over to different parts to solve, and each part focuses on solving its own problems
    • Aspect Oriented Programming is one of the separation of concerns technology
    • The code implementation of the generalization function is the aspect aspect
    • Aspect is to AOP, Class is to OOP, Bean is to Spring
  • original implementation

  • Increase system requirements without changing business code
  • @Aspect: Tell Spring that this is a general logic that needs to be woven, and the class it modifies also needs to be managed by Spring as a bean, so you can use @Component
  • @Pointcut: Tell Spring where to weave the logic in Aspect
  • JoinPoint: The place where the aspect can be woven into the logic; it indicates the calling method; the proceed method cannot be called directly, and it can be converted to ProceedingJointPoint before use
  • @Around: Weaving in when the method is executed
  • Return the result of the delegated method
  • @AfterReturning: Call the relevant logic when the method returns the result

  • Notice:
  • Spring does not enable the logic that supports aop annotations by default, you need to tell Spring to enable the logic of aop annotations; that is, add @EnableAspectJAutoProxy annotations

  • Member of AOP

  • If Aspect is compared to a class, Advice is the method inside
    • Aspect: an entity object that modularizes and encapsulates cross-cutting concern logic
    • Notify Advice: It is like a method in Class, and it also defines the timing of weaving logic
    • Connection point Joinpoint, where Advice is allowed
    • Spring AOP only supports method-level Joinpoint by default
    • Entry point Pointcut: define a series of rules to filter Joinpoint
    • Target object Target: the object that meets the Pointcut condition and is to be woven into the crosscutting logic
  • Weaving: Integrating Aspect's modular cross-cutting concerns into OOP
  • Weaver: The executor who completes the weaving process, such as ajc
  • Spring AOP will use a set of classes as weavers to complete the final weaving operation
  • Types of Advice

  • BeforeAdvice: Advice executed before JoinPoint
  • AfterAdvice: like finally in try...catch...finally (will be executed regardless of whether an exception is thrown)
  • AfterReturningAdvice: Executed after the Joinpoint execution process returns normally (if an exception is thrown during the period, it will not be executed)
  • AfterThrowingAdvice: It will only be triggered if an exception is thrown during the execution of the Joinpoint
  • Around Advice: Executed before and after Joinpoint, the most commonly used Advice
  • Execution order of a single Aspect

  • First execute the logic of the upper body of @Around, that is, before calling the proceed method, then this is the logic in @Before, and then execute the method of the target object joinpoint
  • Then there is the lower body logic (after proceed) that executes the @Around method, followed by @After
  • If it returns normally, call @AfterReturing, otherwise call @AfterThrowing (provided that there is no catch-related exception in Around, just throw it or you won’t come to this step)
  • Execution order of multiple Aspects

  • The smaller the order value, the higher the priority
  • Input operations with high priority will be executed first, and output operations with low priority will be executed first
  • Introduction-Introduction Advice

  • Introduces a new interface for the target class without requiring any implementation by the target class
  • Make the target class transform into a new interface object during use, and call the method of the new interface
  • @DeclareParent can implement
  • Proxy mode

  • Proxy role: proxy class
  • Proxied role: Proxied class
  • Abstract topics: abstract classes or interfaces
  • Both the proxy class and the proxy class need to inherit or implement the abstract theme, and the proxy class should be used when instantiating, and the user only needs to program for the interface or abstract class
  • Spring AOP is to implement a proxy class to replace the implementation class to provide external services
  • example:
    • The user pays with Alipay, and the user does not need to care about how Alipay withdraws from the bank card and transfers the money to the store
    • Withdrawing from the bank card and transferring to the store will entrust Alipay to make the adjustment
    • Alipay as an agent

  • Use AlipayToC as a proxy for ToCPaymentImpl
  • Main function test:

  • The above is a static proxy: the proxy object is implemented at compile time
  • It cannot meet business needs, because we need to implement a proxy object separately if the target objects are different

  • For different target objects, it is necessary to implement a proxy object separately, and the logic of the proxy object is the same, and a one-to-one corresponding implementation class must be created, which is also the limitation of OOP
  • JDK dynamic proxy

  • The class is loaded through the class loader, and the process mainly does 3 things
  • 1 --- Obtain the binary byte stream of the corresponding class file through the class with the package name
  • 2---According to the read byte stream, convert the representative static storage structure into a runtime data structure (the data structure can only be accessed by the outside world)
  • 3---Generate a Class object representing the class as the data access entry of the class in the method area
  • The byte stream can define the behavior of the class, change or generate a new byte stream according to certain rules
  • Weaving the aspect logic into it to make it dynamically generate classes woven into the aspect logic, this mechanism is a dynamic proxy mechanism
  • According to the interface or target class, calculate the bytecode of the proxy class and load it into the JVM
  • JDK dynamic proxy summary:
  • The Proxy class in the java reflection package can call newProxyInstance to create a proxy class object
  • Pass in three parameters:
    • One is the class loader of the proxy class
    • One is an array of all implemented interfaces
    • One is to call the implementation class of the processor
  • Once the proxy object is created, the proxy object can execute the method of the interface implemented by the proxy class
  • When executing the method, it will first execute the invoke method in the call processor implementation class
  • The invoke method can enhance the function of the proxy class
  • JDK dynamic proxy of the realization principle of Spring AOP

  • Static proxy: implement before compilation, and the proxy class is an actual class file after completion
  • The dynamic proxy is dynamically generated. After the compilation is completed, there is no actual class file, but the bytecode of the class is dynamically generated at runtime and loaded into the JVM.
    • It is required that the proxied class must implement the interface
    • The proxy object is not required to implement the interface, so the logic of the proxy object can be reused
  • InvocationHandler
  • Aspect that is only used to manage cross-cutting logic in a unified manner
  • Only classes that implement the InvocationHandler interface have the proxy function

    • proxy: the real proxy object
    • method: the method instance of the target object to be called (corresponding to the above example is the pay() method instance of ToBPaymentImpl)
    • args: the parameters that need to be used in the method
  • Static proxy needs to explicitly call the method of proxy class, such as toCProxy.pay() above
  • For dynamic proxies, the method of the target object is called explicitly, not the method of the proxy class.
  • Dynamic proxy is the method of calling ToCPaymentImpl directly, and static proxy is the method of calling proxy class
  • Proxy
  • Mainly used to create dynamic proxy classes

    • ClassLoader loader: class loader
    • Class[] interfaces: What kind of interface array is provided to the proxy class, and the proxy class will eventually implement these interfaces
    • InvocationHandler h: Which InvocationHandler implementation class instance will be associated with when the current dynamic proxy method is called
  • Used to encapsulate general cross-cutting logic equivalent to Aspect
  • The object used to save the proxy is the target class
  • To execute the proxied method, invoke needs to pass in the proxied instance and parameters

  • Call proxy.newProxyInstance in the tool class to create a corresponding dynamic proxy for AlipayInvocationHandler
  • Generate an instance of the proxy class

  • main function call

  • The JDK dynamic proxy mechanism works by allowing the dynamic proxy class to implement the same interface as the proxy class to replace the proxy class during operation.
  • CGLIB dynamic proxy of the implementation principle of Spring AOP

  • Use CGLib to implement dynamic proxy, completely free from the restriction that the proxy class must implement the interface
  • Moreover, the bottom layer of CGLib adopts the ASM bytecode generation framework, and uses bytecode technology to generate proxy classes, which is more efficient than using Java reflection
  • The only thing to note is that CGLib cannot proxy methods declared as final, because the principle of CGLib is to dynamically generate subclasses of the proxy class
  • Code Generation Library: Code Generation Library
    • The proxy class is not required to implement the interface
    • It mainly encapsulates the ASM Java bytecode manipulation framework internally
    • CGLIB works great for classes where proxies don't generate interfaces
    • Dynamically generate subclasses to override non-final methods, bind hooks to call back custom interceptors (essentially, for classes that require CGLIB proxies, CGLIB just generates subclasses to override non-final methods, bind hooks to call back custom interceptors device)
  • MethodInterceptor
  • It is an interceptor in the AOP project, the target of its interception is the method, not the request
  • Role: define cross-cutting logic Aspect
  • For example, the InvocationHandler of JDK dynamic proxy can define Aspect by implementing MethodInterceptor

  • Corresponding parameters: dynamic proxy object, proxy method object instance, parameter array required by proxy object method, method object instance generated by dynamic proxy
  • Enhancer
  • The Enhancer of the CGLIB library is widely used in Spring AOP as a way to generate proxies
  • It is a bytecode enhancer that can be used to create proxies for classes without interfaces
  • Its function is quite similar to the Proxy class that comes with java.
  • It creates subclasses based on a given class, and all non-final methods have callback hooks
  • You can often see him in Spring. For example, classes annotated with @Configuration will be proxied by Enhancer .
  • When proxying, the bottom layer uses a bytecode to process ASM
  • Example of creating a proxy class:

    • Aspect Aspect Logic
    • Create a proxy class
    • Supports dynamic proxies for classes that do not implement interfaces
    • A class that does not implement an interface
    • main function test
  • CGLIB supports the weaving of classes that implement interfaces and the weaving of classes that do not implement interfaces
  • JDK dynamic proxy and CGLIB

  • Implementation Mechanism:
    • JDK dynamic proxy: based on the reflection mechanism, it is required that the business class must implement the interface
    • CGLIB: Based on the ASM mechanism, generate subclasses of business classes as proxy classes
  • Advantages of JDK dynamic proxy:
    • JDK is native, and it is more reliable to run in JVM (no additional jar package dependencies are required)
    • Smoothly support the upgrade of JDK version (while cglib needs to be upgraded to support the use on the new jdk)
  • Advantages of CGLIB:
    • The proxy object does not need to implement the interface, and can realize the non-intrusion of the proxy class
    • Using bytecode technology to generate proxy classes is more efficient than using Java reflection
  • The underlying mechanism of Spring AOP:
    • Coexistence of CGLIB and JDK dynamic proxy
    • Default policy: If the bean implements the interface, use JDK, otherwise use CGLIB
  • Why does CGLIB support agents that implement interfaces as well as agents that do not implement interfaces, and use JDK agents?
    • Because the JDK dynamic agent does not depend on other packages, and has good compatibility and performance
  • Self-developed framework AOP mechanism 1.0

  • Use CGLIB to achieve: no need for business classes to implement interfaces, relatively flexible
  • Ideas:
    • Solve the problem of marking (identify Aspect and Advice), define the skeleton of crosscutting logic
    • Define the execution order of Aspect crosscutting logic and proxy methods
    • Weave crosscutting logic into proxied objects to generate dynamic proxy objects
  • Solve the marking problem of crosscutting logic and define the Aspect skeleton
  • step:
    • Define annotations related to crosscutting logic
    • Defines a crosscutting logic skeleton for external use
  • Define annotations:

  • value indicates that the cross-cutting logic currently marked by @Aspect will be woven into those classes marked by attribute value annotation tags
  • For example, when the value is @Controller, it means that the Aspect logic will be woven into all classes marked by @Controller
  • Specify the execution order of @Aspect

  • The definition framework supports several kinds of Advice
  • As a hook method, it is an empty implementation, allowing the user to choose whether to implement it

  • The reason why the hook method is used instead of annotations is mainly for the simplicity of implementation
  • Users only need to inherit DefaultAspect to implement the hook method in it, and then the pre- and post-weaving of target class methods can be realized to meet most of the needs
  • Implement Aspect cross-cutting logic and sequenced execution of proxy methods
    • Create the implementation class of MethodInterceptor
    • Define the necessary member variables---the proxied class and the Aspect list
    • Sort Aspects by Order
    • Implement sequential execution of cross-cutting logic and proxy object methods
  • If an AlipayMethodInterceptor corresponds to an Aspect, there will be problems, because each Aspect must implement the Interceptor method, but it will call the invokeSuper method
  • Call the method of the proxy class. If there are multiple Aspects, the invokeSuper method will be called multiple times
  • At the same time, we can't execute all Aspect's beforeAdvice in ascending order and then execute afterAdvice all the way like Spring, so the one-to-one relationship is not feasible
  • Can one MethodInterceptor correspond to multiple Aspects? OK
  • An ordered Aspect list can be saved in the MethodInterceptor to save the sorted Aspect collection
  • After traversing the Aspect collection, execute the before logic in the Aspect collection sequentially, and then only need to execute the invokeSuper method once, and execute the after logic in the Aspect in reverse order
  • Add cross-cutting logic to the method of the proxy class object, because it is CGLIB, so you must inherit MethodInterceptor
  • Define two member variables
  • Receive the order value corresponding to the implementation class
  • AspectInfo is used to encapsulate the attribute values ​​​​of @Order and DefaultAspect

  • After sorting it, assign it to the corresponding member variable
  • Sorting and logic defining member variables
  • Now that the attribute value of order has been accepted, why is there no attribute value of aspect?
  • When it comes time to pass parameters to the constructor, we have already determined that those aspects are weaving logic for the targetClass. After all, this is the relationship between the binding of the two.
  • Therefore, the value of the aspect tag has been used to determine the relationship between the two before creating an instance of the class, so there is no need to pass it
  • test:
  • Guide package:

  • accomplish:

  • It is not enough to implement MethodInterceptor, Handler is also required to create dynamic proxy objects

  • Weave crosscutting logic into proxied objects to generate dynamic proxy objects
  • Two kinds of beans are selected from the container, one is the bean marked by Aspect, and the other is the bean that is proxied
  • Obtain the container singleton instance in the constructor and assign it to the member variable
  • Don't forget to put the classes marked by the Aspect tag into the Spring container for management

  • The attribute values ​​in the class marked by Aspect may be different (that is, the set of target classes to be woven is different, and it needs to be classified according to the attribute value of Aspect)
  • The respective Aspect lists are woven into the keys (classes marked by Controller and Service for weaving operations)
  • Get the target class collection before weaving. For example, if you pass in Class, you can get all the Class object instances marked by the Class tag (pass in Controller, and you can get all the object instances marked by the Controller tag)
  • Completed the weaving operation of all bean instances in the container that need to add Aspect cross-cutting logic

  • Dependency injection and AOP weaving, which one will execute first?
  • We hope that the beans are woven into the cross-cutting logic before they can be used by the outside world, which also includes the beans corresponding to the attributes marked by @Autowired
  • So the injection operation of AOP should be executed before the dependency injection
  • The AOP 1.0 of the self-developed framework needs to be improved

  • Aspect only supports the weaving of cross-cutting logic for classes marked by a certain label (it cannot weave some partial classes marked by the Controller label)
  • Need to put on the coat of AspectJ
  • AspectJ framework

  • Provides a complete AOP solution, which is the Java implementation version of AOP
  • Define the aspect grammar and the parsing mechanism of the aspect grammar
  • Provides powerful weaving tools
  • Spring AOP only supports method-level weaving, but AspectJ supports almost all connection points weaving, a complete solution called AOP

  • Since AspectJ is so powerful, why doesn't Spring reuse AspectJ directly?
  • Because the method-level weaving can already meet most of the needs, and the learning cost of Aspect is much higher than that of Spring AOP, and it is not as easy to use as Spring AOP; spend 20% of the cost to complete 80% of the needs
  • Weaving timing of AspectJ framework: static weaving and LTW
    • Weaving at compile time: use ajc to weave aspect logic into classes to generate class files
    • Weaving after compilation: use ajc to modify the class file compiled by javac
    • Weaving during class loading: use java agent to weave aspect logic when loading classes
  • The first two are static weaving, because the aspect logic has been weaved after the class file is compiled (written into the code)
  • Both CGLIB and JDK dynamic proxy rely on the inheritance relationship to generate the proxy object corresponding to the class, that is, there will be an additional dynamic proxy class in the end.
  • Self-developed framework AOP2.0

  • Import jar package

  • Compromise Improvement Framework for AOP
  • Use the smallest transformation cost in exchange for the greatest possible benefit --- clarify the core demands
  • Requirements: In order to make the selection of weaving targets (Pointcut) more flexible
  • That is, it is only necessary to introduce the aspect expression of AspectJ and the related positioning analysis mechanism
  • Create a parsing class to parse AspectJ
  • No longer use fixed annotation tags to filter proxied classes, so change the attribute name under the Aspect tag from value to pointcut, and change the type to String

  • The PointcutParser instance needs to be created and assembled with the relevant syntax tree to recognize the pointcut expression in the annotation Aspect attribute
  • PointcutExpression: It is the product parsed by PointcutParser according to the expression, which is used to judge whether a certain class or method matches the pointcut expression
  • For class-level judgments

  • Fine screening: It is necessary to pass the method in the proxy class into the pointcutExpression method for precise matching
  • Exact match: alwaysMatches

  • It is meaningless to classify according to the attribute value of the aspect tag before, because different pointcut expressions may obtain the same proxied target
  • For example, different expressions can achieve the same goal
  • In addition, we create a special PointcutLoader for each class marked by the Aspect tag to match the target class and target method according to the corresponding expression in the Aspect, that is, the pointcut expression, so there is no need to classify the Aspect

  • Filter out the eligible AspectInfo
  • Use foreach to traverse a certain collection, but when traversing, the collection elements will be removed, and an error will be reported at this time, why?
  • Because the iterator object used in foreach works in an independent thread and will have a mutex lock, the iterator will create a single-column index table pointing to the original object after creation. When the original number changes (that is, the set When changes occur), the contents of the index table will not change synchronously, so when the index pointer moves backwards, the object to be iterated cannot be found, and an exception will be thrown
  • Therefore, the iterator does not allow dynamic changes to the iterated object when it is working.
  • That is, it does not support calling the remove method of the collection to dynamically remove elements during traversal
  • But we can use the remove method of iterator itself to delete the object
  • Because it will maintain the consistency of the previously mentioned index table while deleting the current iteration object
  • Refinement of the preliminary list

  • Pointcut expression analysis and positioning, coarse sieving and fine sieving

  • aop weaving

  • Advice 1 & Aspect

  • Advice 2 & Aspect

  • Target object (Target)

  • Test success:

Guess you like

Origin blog.csdn.net/weixin_59624686/article/details/131276305