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 rulesNotifications: 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 inheritedThe 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
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 processThe api is as follows: Invocationhandler, proxy.newProxyInstanceFor 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 frameworkThe difference between JDK and CGLIB1. 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.
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