Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一、Spring AOP源码解析

一、Spring AOP源码解析

原创
作者头像
冰枫
发布于 2018-05-05 04:23:12
发布于 2018-05-05 04:23:12
1.7K20
代码可运行
举报
文章被收录于专栏:冰枫冰枫
运行总次数:0
代码可运行

在Spring中可以通过xml方式,或者注解方式来实现Aop,如果通过注解方式则需要在xml中配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<aop:aspectj-autoproxy/>

这篇文章详细讲解一下注解方式是如何来实现Aop的。

一、注册beanDefinitionParser

AopNamespaceHandler是aop命名空间的处理类

它注册了解析config、aspectj-autoproxy、scoped-proxy标签的BeanDefinitionParser,spring-configured标签从2.1开始就被移动了context命名空间中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.1 XSD.
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}

我们直接来看AspectJAutoProxyBeanDefinitionParser的代码:

二、aspectj-autoproxy解析入口

解析分成两项工作

1.注册AspectJAnnotationAutoProxyCreator

2.获取子标签,注册到beanDefinition

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
		extendBeanDefinition(element, parserContext);
		return null;
	}

三、注册AspectJAnnotationAutoProxyCreator

1.如果要代理的类实现了接口,则默认使用jdk动态代理否则将使用cglib进行代理

2.如果配置了proxy-target-class为true,将强制使用cglib进行代理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {
	  // 注册registerAspectJAnnotationAutoProxyCreator
		BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
				parserContext.getRegistry(), parserContext.extractSource(sourceElement));
				// 处理xml中配置的aspectj-autoproxy中的proxy-target-class 和 expose-proxy属性
		useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
		// 注册组件
		registerComponentIfNecessary(beanDefinition, parserContext);
	}

顾名思义注册或者升级AspectJAnnotationAutoProxyCreator,如果有优先级更高的AspectJAnnotationAutoProxyCreator,那么升级为优先级更高的AspectJAnnotationAutoProxyCreator,这里不进行详细解释

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

完成了上述工作,AnnotationAwareAspectJAutoProxyCreator就已经在IOC容器中注册完毕了。

四、AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator它层级实现了InstantiationAwareBeanPostProcessor

,学习过Spring IOC容器源码的童鞋应该知道它的postProcessor方法将会在IOC容器中bean的实例化,初始化等等时候被调用。aop的核心也就是在此。

在AbstractAutoProxyCreator类中对这些方法进行了重写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		// 在className和beanName中用"_"连接 例:cn.blingfeng.Test_test
		Object cacheKey = getCacheKey(beanClass, beanName);
		// 如果beanName为空或者bean还未被处理过
		if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
			// 如果不需要代理
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			// 如果为Advisor Advice AopInfrastructureBean 类的实现类 或者 为pointCut则不需要处理
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}
		
		if (beanName != null) {
			// 获取定制的targetSource,可以通过子类重写此方法,来实现不同的机制
			TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
			if (targetSource != null) {
				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;
	}

	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) {
		return true;
	}

	@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {

		return pvs;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
			 // bena进行包装
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 如果bean还未被处理
		if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// bean不需要增强
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// 如果为Advisor Advice AopInfrastructureBean 类的实现类 或者 为pointCut则不需要处理
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// 获取增强
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		// 如果存在增强方法
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 创建代理
			Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

isInfrastructureClass()方法具体实现,如果为Advice或Advisor或AopInfrastrutureBean的实现则返回true

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	protected boolean isInfrastructureClass(Class<?> beanClass) {
		boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
				Advisor.class.isAssignableFrom(beanClass) ||
				AopInfrastructureBean.class.isAssignableFrom(beanClass);
		if (retVal && logger.isTraceEnabled()) {
			logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
		}
		return retVal;
	}

shouldSkip()方法具体实现,

首先获取所有的增强,可以看到上面有一个todo注释:考虑缓存aspect names,因为findCandidateAdvisors()这个方法,我们在后面的获取增强方法,进行代理,还要用到,所以弄一个Set集合进行缓存可以提升性能。

然后遍历增强,如果为AspectJPointcutAdvisor派生类则返回true

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
	protected boolean shouldSkip(Class<?> beanClass, String beanName) {
		// TODO: Consider optimization by caching the list of the aspect names
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
			if (advisor instanceof AspectJPointcutAdvisor) {
				if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
					return true;
				}
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

获取增强

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

1.首先获取所有的增强

2.寻找适用于该bean的增强

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 1.
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 2.
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

我们虽使用了注解来使用aop,但是xml仍可以进行配置,因此需要获取xml和注解配置的增强

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
	protected List<Advisor> findCandidateAdvisors() {
		// 获取xml中配置的增强
		List<Advisor> advisors = super.findCandidateAdvisors();
		// 获取注解配置的增强
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		return advisors;
	}

xml和注解获取增强不详细描述,xml无非就是进行解析获取。注解的话就是获取所有的beanName,然后扫描这些bean的Aspect注解,然后获取切点,增强等等。

然后根据xml或者注解中配置的表达式获取适用于此bean的增强。下篇进行代理创建的分析

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
2 条评论
热度
最新
最近社区看到了很多关于ASP的文章,很实用
最近社区看到了很多关于ASP的文章,很实用
回复回复点赞举报
good
good
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
Spring AOP 注解方式源码解析
在上篇文章 Spring AOP 功能使用详解 中,知道了 Sprig AOP 的一个详细用法,现在的看看Spring 中是如何实现的。
Java技术编程
2020/05/20
5470
【Spring注解驱动开发】AOP核心类源码解析,这是最全的一篇了!!
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:
冰河
2020/10/29
3010
【Spring注解驱动开发】AOP核心类源码解析,这是最全的一篇了!!
spring-aop 之 aop:config
文章目录 开头 aop:config 解析 proxy-target-class & expose-proxy aop:pointcut aop:advisor aop:aspect aop:d
MickyInvQ
2021/10/13
1.3K0
Spring AOP 原理源码深度剖析
概述 AOP(Aspect-Oriented Programming) 面向切面编程。Spring Aop 在 Spring框架中的地位举足轻重,主要用于实现事务、缓存、安全等功能。本篇主要是对源码进行深度分析。
方志朋
2019/06/21
1.1K0
你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?
在上篇文章中(Spring中AOP相关的API及源码解析,原来AOP是这样子的)我们已经分析过了AOP的实现的源码,那么Spring是如何将AOP应用到Bean的生命周期的呢?这篇文章就带着大家来探究下这个问题。本文我们要分析的代码还是位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean这个方法中,在《我们来谈一谈Spring中的属性注入 》这篇文章中,我们已经分析过了populateBean这个方法,
程序员DMZ
2020/07/20
6190
你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?
你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?
在上篇文章中(Spring中AOP相关的API及源码解析,原来AOP是这样子的)我们已经分析过了AOP的实现的源码,那么Spring是如何将AOP应用到Bean的生命周期的呢?这篇文章就带着大家来探究下这个问题。本文我们要分析的代码还是位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean这个方法中,在《我们来谈一谈Spring中的属性注入 》这篇文章中,我们已经分析过了populateBean这个方法,
程序员DMZ
2020/07/05
1.8K0
Spring如何实现AOP,请不要再说cglib了!
最近工作中我都是基于注解实现 AOP 功能,常用的开启 AOP 的注解是 @EnableAspectJAutoProxy,我们就从它入手。
java进阶架构师
2020/09/30
5000
Spring如何实现AOP,请不要再说cglib了!
Spring是如何实现AOP的
在AbstractAutoProxyCreator中存在以下两个方法,一个是对应循环依赖中如何提前暴露Bean的引用地址,另一个则是根据Bean实例获取最终Bean的后置处理器中,二者都调用了一个方法:wrapIfNecessary,这就是AOP的入口,前者对应开发者在注入单例bean时获取到代理对象(例如Service层注入其他Service得到的是其代理对象),后置则对应普通流程的增强类方法。
默 语
2024/11/22
1520
Spring 事务初始化源码分析
在上篇文章 Spring 事务使用详解 中详细介绍了 Spring 事务的使用过程,今天就来看下 Spring 事务是如何来实现,比如 Spring 事务在初始化的时候做了什么,Spring 事务是如何进行事务的提交和回滚的;为了避免篇幅太长,所以分开两篇文章进行分析,这篇文章先来分析下 Spring 事务是如何初始化的,在初始化的时候做了什么。
Java技术编程
2020/05/20
5140
Spring如何实现AOP,请不要再说cglib了!
最近工作中我都是基于注解实现AOP功能,常用的开启AOP的注解是@EnableAspectJAutoProxy,我们就从它入手。
温安适
2019/10/21
1.7K0
Spring如何实现AOP,请不要再说cglib了!
Spring读源码系列之AOP--09---aop源码流程一把拿下
上一篇文章已经详细介绍了两种aop自动代理创建器的导入流程分析,此时我们已经知道了自动代理创建器注册到容器中的流程,下面我们来探究一下,自动代理创建器对具体bean创建代理的流程,这里测试环境还是用上一篇中开头给出的测试环境。
大忽悠爱学习
2022/05/10
2760
Spring读源码系列之AOP--09---aop源码流程一把拿下
【小家Spring】Spring AOP的核心类:AbstractAdvisorAutoProxy自动代理创建器深度剖析(AnnotationAwareAspectJAutoProxyCreator)
上篇博文: 【小家Spring】面向切面编程之—Spring AOP的原理讲解以及源码分析(Cannot find current proxy: Set ‘exposeProxy’ property on ) 已经刚刚结合实例,介绍了Spring AOP的过程以及对源码进行了逐步分析~
YourBatman
2019/09/03
3.1K0
【小家Spring】Spring AOP的核心类:AbstractAdvisorAutoProxy自动代理创建器深度剖析(AnnotationAwareAspectJAutoProxyCreator)
从源码的角度深入理解spring AOP原理及流程
Spring作为java开发必用的开源框架之一,必然有它非常优秀的且不可替代的地方,其中springIOC和Aop就是设计的非常优秀的地方,今天一起来学习一下spring是如何实现AOP
全栈程序员站长
2022/07/04
4560
从源码的角度深入理解spring AOP原理及流程
Spring AOP事务01
XML中的tx:annotation-driven 注解用于开启事务,在TxNameSpaceHandler 中,进行自注册增强,springboot 是通过 @EnableTransactionManagement进行注册和解析
用户3293499
2024/09/01
1870
基于注解的SpringAOP源码解析(三)
在之前的2篇文章:AOP源码分析(一)AOP源码分析(二) 中,我们搭建了SpringAOP源码分析的环境,介绍了@EnableAspectJAutoProxy注解和postProcessBeforeInstantiation方法是如何加载所有增强的。本篇文章则将描述一下AOP中剩余的实现逻辑
Java学习录
2019/08/21
4570
基于注解的SpringAOP源码解析(三)
Spring事务AOP实现原理
此篇文章需要有SpringAOP基础,知道AOP底层原理可以更好的理解Spring的事务处理。
用户4283147
2022/10/08
5710
Spring事务AOP实现原理
5.2 spring5源码--spring AOP源码分析三---切面源码分析
引入AOP, 我们需要在配置文件中增加@EnableAspectJAutoProxy代理. 那么想要去掉AOP的引入, 只需要将这个注解注释掉就可以了. 这个注解解释整个AOP的入口.
用户7798898
2021/02/22
5770
5.2 spring5源码--spring AOP源码分析三---切面源码分析
Spring AOP 中的代理对象是怎么创建出来的?
今天和小伙伴们聊一聊 Spring AOP 中的代理对象是怎么创建出来的,透过这个过程再去熟悉一下 Bean 的创建过程。
江南一点雨
2023/09/09
8170
Spring AOP 中的代理对象是怎么创建出来的?
Spring读源码系列之AOP--07---aop自动代理创建器(拿下AOP的最后一击)
本系列列举的源码中,很多类没有展开讲,是因为之前的系列文章一直在对aop基础组件进行介绍,因此一定要按照顺序看本系列,否则观看本篇文章的时候,越往后看,越发觉得本文模糊不清,只会粘贴源码,实则不然,因为很多类前文已经讲过,如果本文再展开讲解,那么将无法突出重点
大忽悠爱学习
2022/05/10
1.1K0
Spring读源码系列之AOP--07---aop自动代理创建器(拿下AOP的最后一击)
Spring源码解析(九):AOP源码之@Aspect所有相关注解解析
InstantiationModelAwarePointcutAdvisorImpl构造函数 创建具体通知
Java微观世界
2025/01/21
4420
Spring源码解析(九):AOP源码之@Aspect所有相关注解解析
推荐阅读
相关推荐
Spring AOP 注解方式源码解析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验