Above: spring5.x-listener principle and source code implementation
Articles in this series:
spring5.x-listener principle and source code implementation
spring5.x-solve circular dependency analysis
spring5.x-IOC module source code learning
Spring5.x introduction and matching spring source code reading environment
What is springAop?
Spring AOP (Aspect-Oriented Programming) is an important feature of the Spring framework, which provides a programming paradigm based on cross-cutting concerns. AOP allows developers to separate cross-cutting concerns (such as logging, transaction management, security, etc.) from core business logic, resulting in better code structure and maintainability.
In traditional object-oriented programming, functionality is usually scattered among the various modules of the application, such as access to the database, exception handling, and so on. This leads to a lot of repetitive code, which is difficult to maintain and extend. AOP provides a way to define cross-cutting concerns in a declarative way without modifying the original code, and apply them to multiple modules of the application.
In Spring AOP, the cross-cutting concern is called the aspect (Aspect), and the object being cut into is called the target object (Target Object). The implementation of AOP depends on proxy mode and dynamic proxy technology. Spring provides two main AOP implementation methods:
Proxy-based AOP: This method uses JDK dynamic proxy or CGLIB dynamic proxy to create a proxy object and weave aspects into the method call of the target object. If the target object implements the interface, the JDK dynamic proxy is used; otherwise, the CGLIB dynamic proxy is used. Proxy-based AOP can weave aspect logic into the target object at runtime.
Pure Java compile-time implanted AOP: This approach implements AOP through compile-time bytecode enhancement, which uses AspectJ's annotations and compiler to weave aspects into the target object's bytecode during compilation. Unlike proxy-based AOP, pure Java compile-time embedded AOP does not require dynamic proxies at runtime and therefore has higher performance.
Spring AOP supports the following common aspect functions:
Before advice: Actions performed before the target method is called.
After advice: Actions performed after the target method is called, regardless of whether an exception occurs.
After returning advice: Actions performed after the target method successfully returns a result.
Exception advice (After throwing advice): Actions performed after the target method throws an exception.
Around advice: surrounds the target method call and can perform custom operations before and after the call.
Spring AOP is a mechanism for implementing aspect-oriented programming, which can help developers better manage cross-cutting concerns, and provides flexible methods to handle common functions such as logging, transactions, and security, and improve code reusability and availability. Maintainability.
Basic use of spring AOP
Please refer to the article I originally wrote: spring's AOP
spring AOP source code learning
AOP initialization
When spring is initialized to org.springframework.context.support.AbstractApplicationContext#refresh(), there is a notification processor initialization, which will call the following method for initialization (other ignore see the previous article)
When @EnableAspectJAutoProxy(proxyTargetClass = true) is annotated on a custom configuration class or startup class, it indicates that the project is enabled for AOP.
Configure startup class annotations:
@EnableAspectJAutoProxy
Enter @EnableAspectJAutoProxy and find that AspectJAutoProxyRegistrar.class is imported through @import.
Code location: org.springframework.context.annotation.AspectJAutoProxyRegistrar#registerBeanDefinitions
Class Diagram:
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//通过反射方式进行注入
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
//cglib代理
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
//jdk代理(同理)
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
That is to say, when spring starts, it will use the @EnableAspectJAutoProxy annotation to identify whether to start aop. If it is added by default, this aop will be started. The class AspectJAutoProxyRegistrar is imported through @import in this annotation for initialization, and there are A registerBeanDefinitions method is performed.
Then it will enter: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
Note: In fact, the top layer here is AnnotationAwareAspectJAutoProxyCreator, but the bottom layer is AbstractAutowireCapableBeanFactory. Look at the class diagram below:
Class location: org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#initBeanFactory
Here is the factory class that initializes the bean. In fact, it is still in refresh here.
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
//用于管理切面通知的构建和配置,用于实现横切关注点的处理。
this.aspectJAdvisorsBuilder = new AnnotationAwareAspectJAutoProxyCreator.BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
You have to pay attention here, and the next step is to adjust the IOC (you can read the original article if you don’t understand it).
Code location: org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
//缓存获取key
Object cacheKey = this.getCacheKey(beanClass, beanName);
//为空或不包含
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
//如果有有解析直接返回
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
//如果不是基础bean就直接跳过
if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
//如果beanName不是空
if (beanName != null) {
TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
//获取目标路劲不为空 通过工理方式获取并放到代理缓存中
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
Then enter shouldSkip, this method is mainly used to determine whether to skip a specific bean
代码位置:org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
Iterator var4 = candidateAdvisors.iterator();
Advisor advisor;
do {
if (!var4.hasNext()) {
return super.shouldSkip(beanClass, beanName);
}
advisor = (Advisor)var4.next();
} while(!(advisor instanceof AspectJPointcutAdvisor) || !((AbstractAspectJAdvice)advisor.getAdvice()).getAspectName().equals(beanName));
return true;
}
Through findCandidateAdvisors above, find the findAdvisorBeans method used to build the vdisors of the aspect.
Code location: org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
//获取所有通知者
public List<Advisor> findAdvisorBeans() {
//通知者名称列表
String[] advisorNames = null;
//同步锁
synchronized(this) {
//获取缓存列表
advisorNames = this.cachedAdvisorBeanNames;
//如果为空
if (advisorNames == null) {
//通过从工厂类中去获取(这里不深入前端ioc类似)
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
//然后进行赋值给缓存
this.cachedAdvisorBeanNames = advisorNames;
}
}
//长度为空直接返回空
if (advisorNames.length == 0) {
return new LinkedList();
} else {
//初始化列表
List<Advisor> advisors = new LinkedList();
String[] var3 = advisorNames;
int var4 = advisorNames.length;
//从ioc容器中获取所有的bean名称
for(int var5 = 0; var5 < var4; ++var5) {
String name = var3[var5];
if (this.isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
} else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
} catch (BeanCreationException var11) {
Throwable rootCause = var11.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException)rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name + "' with dependency on currently created bean: " + var11.getMessage());
}
continue;
}
}
throw var11;
}
}
}
}
return advisors;
}
}
Then enter the isAspect method.
Code location: org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
public boolean isAspect(Class<?> clazz) {
return this.hasAspectAnnotation(clazz) && !this.compiledByAjc(clazz);
}
private boolean hasAspectAnnotation(Class<?> clazz) {
return AnnotationUtils.findAnnotation(clazz, Aspect.class) != null;
}
代码位置:org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
//获取aspect类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
//获取切面类的名称
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
//校验切面类
this.validate(aspectClass);
//通过包装类包装
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList();
//获取所有切面类 @PointCut注解的方法
Iterator var6 = this.getAdvisorMethods(aspectClass).iterator();
while(var6.hasNext()) {
Method method = (Method)var6.next();
//循环解析切面中的方法
Advisor advisor = this.getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
Field[] var12 = aspectClass.getDeclaredFields();
int var13 = var12.length;
for(int var14 = 0; var14 < var13; ++var14) {
Field field = var12[var14];
Advisor advisor = this.getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
The following is how to obtain the aspect class. Of course, this is in order.
代码位置:org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisorMethods
//获取一个切面类(aspectClass)中的方法列表
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new ArrayList();
ReflectionUtils.doWithMethods(aspectClass, new MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException {
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}
});
Collections.sort(methods, METHOD_COMPARATOR);
return methods;
}
The order is determined at the time of initialization, from head to head, that is, the order we execute: Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class}
static {
CompoundComparator<Method> comparator = new CompoundComparator();
comparator.addComparator(new ConvertingComparator(new InstanceComparator(new Class[]{Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class}), new Converter<Method, Annotation>() {
public Annotation convert(Method method) {
AspectJAnnotation<?> annotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return annotation != null ? annotation.getAnnotation() : null;
}
}));
comparator.addComparator(new ConvertingComparator(new Converter<Method, String>() {
public String convert(Method method) {
return method.getName();
}
}));
METHOD_COMPARATOR = comparator;
}
Through the previous logic, we finally reach this InstantiationModelAwarePointcutAdvisorImpl to create a specific implementation of aop.
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
//切面定义切点
this.declaredPointcut = declaredPointcut;
//切面对象
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
//切面方法名称
this.methodName = aspectJAdviceMethod.getName();
//切面参数类型
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
//切面方法对象
this.aspectJAdviceMethod = aspectJAdviceMethod;
//asperctj通知工厂
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
//aspect实例工厂
this.aspectInstanceFactory = aspectInstanceFactory;
//切面具体顺序
this.declarationOrder = declarationOrder;
//切面名称
this.aspectName = aspectName;
//判断是否需要延迟加载
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Pointcut preInstantiationPointcut = Pointcuts.union(aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
this.pointcut = new InstantiationModelAwarePointcutAdvisorImpl.PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
} else {
this.pointcut = this.declaredPointcut;
this.lazy = false;
this.instantiatedAdvice = this.instantiateAdvice(this.declaredPointcut);
}
}
The above is ultimately the creation of the bean.
Initialization alone is just such a big code (part of it is omitted~), it’s really~
dynamic proxy
Spring's default proxy method is JDK dynamic proxy, but if the target object does not implement the interface, it will automatically switch to CGLIB dynamic proxy. This ensures that the AOP function can be used in most cases without the need to manually configure the proxy method.
After the previous initialization, when the method is called, spring will have an interception chain by default to connect the proxy and the aspect, and match the proxy through invoke reflection.
Code location: org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
//AOP 拦截器链可以按照顺序依次执行拦截器或拦截器通知的逻辑
public Object proceed() throws Throwable {
//最后一个拦截器会进入
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//返回切点
return this.invokeJoinpoint();
} else {
//获取需要运行的拦截器
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
} else {
//执行拦截器方法
return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
}
}
}
The above method has always been executed recursively.
Then enter: invoke method
Code location: org.springframework.aop.interceptor.ExposeInvocationInterceptor#invoke
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = (MethodInvocation)invocation.get();
invocation.set(mi);
Object var3;
try {
var3 = mi.proceed();
} finally {
invocation.set(oldInvocation);
}
return var3;
}
You can see that this is the interceptor that is finally executed, and the chain of responsibility design pattern is used to make recursive calls. The order is: Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class} which is consistent with the initialization order.
As for students who don’t understand the chain of responsibility design model, please read: Design Pattern-Responsibility Chain Pattern
at last
Spring aop is relatively difficult to debug, especially for various agents. If you don’t understand this article, please read the following reference articles for more reference. Of course, if you can understand it, it is recommended to look at the logs in some open source frameworks or some middleware or related components integrated by spring, springboot, and springcloud. It is worth seeing that these implementation logics and principles are actually the same. Of course, what I see more in my official work is the implementation of tools such as global logs and custom interceptors such as encryption.
reference:
https://cloud.tencent.com/developer/article/1512235
https://www.cnblogs.com/FatalFlower/p/15572344.html
https://blog.csdn.net/pengjianglilive/article/details/109608986