AOP (Aspect Oriented Programming)

1. What is AOP

AOP is the abbreviation of Aspect Oriented Programming, which means: aspect-oriented programming, a technology that realizes the unified maintenance of program functions through pre-compilation and runtime dynamic proxy. AOP is a continuation of OOP (Object-Oriented Programming), a hot spot in software development, an important content in the Spring framework, and a derivative paradigm of functional programming. AOP can be used to isolate various parts of the business logic, thereby reducing the coupling degree between the various parts of the business logic. Using AOP for programming can reduce the intrusiveness of the code, improve the reusability of the program, and improve the efficiency of development. .

To put it simply, aop is a kind of thought and specification. By choosing different methods (which can be in different classes) at different times (before method execution, after execution, before and after returning, after throwing an exception...), to The selected method adds processing logic uniformly.

springAOP is a concrete implementation of the AOP idea, but it only implements the enhancement of the method, not the enhancement of the property

2. Typical application scenarios of AOP

  • Unified logging 
  • Unified method execution time statistics
  • Unified return formatting
  • Unified exception handling
  • Transaction opening and committing

3. Core knowledge points about AOP

Aspect class: define that this class is an aspect class

PointCut: Define the method to be enhanced

The role of Pointcut is to provide a set of rules ( described using AspectJ pointcut expression language ) to match Join Points, and add Advice to Join Points that satisfy the rules

Notifications: Define implementation logic for method enhancements

It defines what an aspect is, when to use it, describes the work to be done by the aspect, and solves the problem of when to perform this work.

Pointcut expression description

AspectJ supports three kinds of wildcards:
* : Match any character, only one element (package, class, or method, method parameter).
* .. : Match any character, can match multiple elements, and must be used in conjunction with * when representing a class .
+ : Indicates that all classes of the specified class are matched according to the type, and must be followed by the class name, such as com.cad.Car+, indicating that all subclasses of the class are inherited
The class includes itself.
Pointcut expressions are composed of pointcut functions, among which execution() is the most commonly used pointcut function for matching methods. The syntax is:
execution ( <modifier> < return type > < package.class.method ( parameter ) > <exception> )
Modifiers and exceptions can be omitted.
expression example

Define related notifications

The notification defines the specific business to be executed by the intercepted method. For example, the user login authority verification method is the specific business to be executed. In Spring AOP, the following annotations can be used on the method, which will set the method as a notification method, and notify the method to call after the conditions are met:
Pre-notification uses @Before: the notification method will be executed before the target method is called.
Post-notification uses @After: the notification method will be called after the target method returns or throws an exception.
Notify after returning using @AfterReturning: The notification method will be called after the target method returns.
Use @AfterThrowing to notify after throwing an exception: the notification method will be called after the target method throws an exception.
Surround advice uses @Around: advice to wrap the notified method, and perform custom behavior before and after the method is notified.

Four. The realization principle of AOP

Spring AOP is built on the basis of dynamic proxy , so Spring 's support for AOP is limited to method-level interception .
Spring AOP supports JDK Proxy and CGLIB to realize dynamic proxy. By default, the class that implements the interface (the proxy class) uses AOP to generate a proxy class based on JDK, and the class that does not implement the interface generates a proxy class based on CGLIB .
For dynamic proxies implemented using JDK: the proxy class and the proxied class must implement the same interface, which will be used during the implementation process
 The api is as follows: Invocationhandler, proxy.newProxyInstance
For dynamic proxies implemented based on GCLIB: inherit the original class (the original class cannot be modified by final), it is a third-party framework that specifically generates proxy classes, and is generated based on the asm bytecode framework
The difference between JDK and CGLIB
1. JDK implementation requires that the proxy class must implement the interface, and then through InvocationHandler and Proxy , the proxy class object is dynamically generated in memory at runtime. The proxy object is realized by implementing the same interface (similar to the static proxy interface implementation) way), but the proxy class is dynamically woven into the unified business logic bytecode at runtime.
2. CGLIB implementation, the proxy class may not implement the interface, and the proxy class object is dynamically generated at runtime by inheriting the proxy class.
Weaving : When the agent is generated
Weaving is the process of applying the aspect to the target object and creating a new proxy object. The aspect is woven into the target object at the specified connection point.
There are several points in the target object's lifecycle where weaving can take place:
Compile time: Aspects are woven in when the target class is compiled. This approach requires a special compiler. AspectJ 's weaving compiler is based on this
The way weaves into the aspect.
Class loader: Aspects are woven when the target class is loaded into the JVM . This approach requires a special class loader ( ClassLoader ) , which can enhance the bytecode of the target class before it is introduced into the application. AspectJ5 's load-time weaving ( load-timeweaving.LTW )
supports weaving into aspects in this way.
Runtime: Aspects are woven in at a certain point in the application's runtime. Generally, when weaving an aspect, the AOP container will dynamically create a proxy object for the target object. Spring AOP weaves aspects in this way.

5. Implementation of AOP

The proxy classes implemented by JDK and GCLIB are as follows:

JDK

import org.example.demo.service.AliPayService;
import org.example.demo.service.PayService;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//动态代理:使用JDK提供的api(InvocationHandler、Proxy实现),此种方式实现,要求被代理类必须实现接口
public class PayServiceJDKInvocationHandler implements InvocationHandler {
    //目标对象即就是被代理对象
    private Object target;

    public PayServiceJDKInvocationHandler(Object target) {
        this.target = target;
    }

    //proxy代理对象
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws
            Throwable {
//1.安全检查
        System.out.println("安全检查");
//2.记录日志
        System.out.println("记录日志");
//3.时间统计开始
        System.out.println("记录开始时间");
//通过反射调用被代理类的方法
        Object retVal = method.invoke(target, args);
//4.时间统计结束
        System.out.println("记录结束时间");
        return retVal;
    }

    public static void main(String[] args) {
        PayService target = new AliPayService();
//方法调用处理器
        InvocationHandler handler =
                new PayServiceJDKInvocationHandler(target);
//创建一个代理类:通过被代理类、被代理实现的接口、方法调用处理器来创建
        PayService proxy = (PayService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                new Class[]{PayService.class},
                handler
        );
        proxy.pay();
    }
}

GCLIB

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.example.demo.service.AliPayService;
import org.example.demo.service.PayService;

import java.lang.reflect.Method;

public class PayServiceCGLIBInterceptor implements MethodInterceptor {
    //被代理对象
    private Object target;

    public PayServiceCGLIBInterceptor(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy
            methodProxy) throws Throwable {
//1.安全检查
        System.out.println("安全检查");
//2.记录日志
        System.out.println("记录日志");
//3.时间统计开始
        System.out.println("记录开始时间");
//通过cglib的代理方法调用
        Object retVal = methodProxy.invoke(target, args);
//4.时间统计结束
        System.out.println("记录结束时间");
        return retVal;
    }

    public static void main(String[] args) {
        PayService target = new AliPayService();
        PayService proxy = (PayService) Enhancer.create(target.getClass(), new
                PayServiceCGLIBInterceptor(target));
        proxy.pay();
    }
}


 

Six. The use of AOP

There are two main ways to use Spring AOP:
① Use aspectj-style annotations for development:

add dependencies

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

Define notification timing and notification logic

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @author tongchen
 * @create 2023-05-08 11:14
 */
@Aspect
//将配置加载到容器中
@Component
public class AopConfig {
    //定义切点
    //包后面一定要有一个空格
    @Pointcut("execution(* com.ljl..service.*Service.*(..))")
    public void pointCut(){

    }
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint){

        //pointcut匹配的方法
        try {
            Long start=System.currentTimeMillis();
            Object proceed = joinPoint.proceed();
            Long end=System.currentTimeMillis();
            System.out.println("方法运行的时间:"+(end-start));
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        return null;
    }

}

Define pointcut method

import org.springframework.stereotype.Service;

import java.util.ArrayList;

/**
 * @author tongchen
 * @create 2023-05-08 11:13
 */
@Service
public class AspectService {
    public Object timeTest(){
        //模拟获取数据库中的数据
        return new ArrayList<Integer>();
    }
}

② Define a class to implement MethodInteceptor

Guess you like

Origin blog.csdn.net/m0_65431718/article/details/130556138