3 | Spring:AOP实现原理

看给容器中注册了什么组件,这个组件什么时候工作,功能是什么?@EnableAspectJAutoProxy工作流程①首先从@EnableAspectJAutoProxy注解入手,它使用@Import注解,加入了一个实现了ImportBeanDefinitionRegistrar的类,叫做Aspect

看给容器中注册了什么组件,这个组件什么时候工作,功能是什么?

@EnableAspectJAutoProxy工作流程

①首先从@EnableAspectJAutoProxy注解入手,它使用@Import注解,加入了一个实现了ImportBeanDefinitionRegistrar的类,叫做AspectJAutoProxyRegistrar

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
	boolean proxyTargetClass() default false;
	boolean exposeProxy() default false;
}

②也就是说它会往IOC容器中加入相应的bean,到底加入了什么呢?

@Override
public void registerBeanDefinitions(
		AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

	AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

	AnnotationAttributes enableAspectJAutoProxy =
			AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
	if (enableAspectJAutoProxy != null) {
		if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		}
		if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
			AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
		}
	}
}

registerBeanDefinitions()方法开始,可以一直跟到AopConfigUtils.registerOrEscalateApcAsRequired(),在这个函数里面,它往IOC容器中注册了一个AnnotationAwareAspectJAutoProxyCreator,名称为AUTO_PROXY_CREATOR_BEAN_NAME,即org.springframework.aop.config.internalAutoProxyCreator

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
	return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, @Nullable Object source) {

	return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
		Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	// 此时不存在bean的定义
	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
		if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
			int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
			int requiredPriority = findPriorityForClass(cls);
			if (currentPriority < requiredPriority) {
				apcDefinition.setBeanClassName(cls.getName());
			}
		}
		return null;
	}

    // 创建AnnotationAwareAspectJAutoProxyCreator的bean,
    // 名称为AUTO_PROXY_CREATOR_BEAN_NAME
	RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
	beanDefinition.setSource(source);
	beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
	beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}

AnnotationAwareAspectJAutoProxyCreator

了解AnnotationAwareAspectJAutoProxyCreator的功能,就等于知道了AOP的原理。首先看看它的继承关系图。

它的父类中,实现了两个接口,这两个接口参见bean的生命周期,所以搞清楚这两个接口在何时工作、工作内容即可搞明白AOP的整理流程。

①有一个BeanFactoryAware接口;

②还有一个SmartInstantiationAwareBeanPostProcessor接口,它继承自InstantiationAwareBeanPostProcessor,它继承自BeanPostProcessor,但是与BeanPostProcessor不一样。InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor作用于初始化阶段的前后。

工作时机

BeanFactoryAware

按照上面类图中,从最先实现BeanFactoryAware接口的类,依次往下找相关的实现,即setBeanFactory()方法:

AbstractAutoProxyCreator.setBeanFactory()

@Override
public void setBeanFactory(BeanFactory beanFactory) {
    this.beanFactory = beanFactory;
}

AbstractAdvisorAutoProxyCreator.setBeanFactory()

@Override
public void setBeanFactory(BeanFactory beanFactory) {
    super.setBeanFactory(beanFactory);
    ...
    initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    this.advisorRetrievalHelper = 
        new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}

AnnotationAwareAspectJAutoProxyCreator

@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    super.initBeanFactory(beanFactory);
    if (this.aspectJAdvisorFactory == null) {
        this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
    }
    this.aspectJAdvisorsBuilder =
            new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}

分别打上断点。

SmartInstantiationAwareBeanPostProcessor

按照上面的类图,从最先实现SmartInstantiationAwareBeanPostProcessor接口的类开始,逐步往下寻找相关方法实现,如下:

AbstractAutoProxyCreator

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);

    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

分别打上断点。

工作流程梳理

  1. InstantiationAwareBeanPostProcessor作为一个bean,被加载到beanFactory中。并执行其BeanFactoryAware接口的方法。
  2. 当其他bean初始化时,InstantiationAwareBeanPostProcessor会拦截其他bean的实例化,并创建代理对象返回。也就是执行postProcessBeforeInstantiationpostProcessAfterInitialization

上面的结论是错的,经过后续的debug跟代码,发现最终Divider被Cglib代理是在BeanPostProcessor的afterInitialization中,如下:

其中的创建代理对象的逻辑如下:

Cglib执行代理流程

这个像一个有限套娃,也有点像递归,这种包装办法真的很厉害,很服气。


①AfterThrowing

try {
    return mi.proceed();②
}
catch (Throwable ex) {
    if (shouldInvokeOnThrowing(ex)) {
        invokeAdviceMethod(getJoinPointMatch(), null, ex);
    }
    throw ex;
}


②AfterReturning

Object retVal = mi.proceed();③
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;

③After

try {
    return mi.proceed();④
}
finally {
    invokeAdviceMethod(getJoinPointMatch(), null, null);
}

④Before

this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();⑤

⑤invokeJoinpoint();

Netty源码学习系列④接收消息

Spring Cloud Alibaba Sentinel简易搭建与配置

Spring Boot Admin构建及用途

xxljob分布式定时任务

ELK日志系统搭建 elasticsearch、logstash、kibana

kafka集群搭建

redis集群搭建

Spring Boot自动配置原理

raft算法演示以及nacos的CP与AP

Read more

Volcano 与 Kubernetes GPU 调度学习笔记

本笔记系统整理 Volcano 调度器、Kubernetes 调度框架、GPU Device Plugin、HAMi 等云原生 AI 调度领域的核心知识,适合用于学习、复习和工程实践参考。 目录 * 第一部分:Volcano 入门 * 1. Volcano 是什么 * 2. 安装与快速使用 * 3. 核心特性一览 * 第二部分:Volcano 整体架构 * 4. Volcano 解决的核心问题 * 5. 整体架构与数据流 * 6. 三层抽象模型 * 第三部分:Volcano 核心实现原理 * 7. Session 机制 * 8. Gang Scheduling 实现 * 9. Queue 与 DRF 公平调度

容器镜像(4):镜像的常用工具箱

容器镜像(4):镜像的常用工具箱

前几篇在讲多架构镜像时已经用过 skopeo 和 crane 做镜像复制,这篇系统整理这两个工具的完整能力,同时介绍几个日常操作镜像时同样好用的工具。 一、skopeo:不依赖 Daemon 的镜像瑞士军刀 skopeo 的核心价值是绕过 Docker daemon,直接与 Registry API 交互。上一篇用它做镜像复制和离线传输,但它的能力远不止于此。 1.1 安装 # Ubuntu / Debian sudo apt install -y skopeo skopeo --version # skopeo version 1.15.1 1.2 inspect:免拉取检查镜像元数据 docker inspect 需要先把镜像拉到本地,skopeo inspect 直接向 Registry

容器镜像(3):多架构镜像构建

容器镜像(3):多架构镜像构建

一、什么是多架构镜像 1.1 OCI Image Index 上一篇介绍了单平台镜像的结构:一个 Manifest 指向 Config 和若干 Layer blob。多架构镜像在此之上多了一层——OCI Image Index(也叫 Manifest List),是一个轻量的索引文件,把多个单平台 Manifest 组织在一起: $ docker manifest inspect golang:1.22-alpine { "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests&

容器镜像(2):containerd 视角下的镜像

容器镜像(2):containerd 视角下的镜像

一、为什么需要了解 containerd 如果你只用 docker run 跑容器,从来不关心底层,那可以不了解 containerd。但如果你在用 Kubernetes,或者想真正理解"容器运行时"是什么,containerd 是绕不开的。 事实上,当你执行 docker run 的时候,containerd 早就在后台悄悄工作了——Docker 从 1.11 版本开始,就把核心运行时剥离出来交给 containerd 负责。 1.1 Docker 的架构演变 早期的 Docker(1.10 及之前)是一个"大一统"的单体程序:一个 dockerd