学习笔记---springboot的aop实现简单分析

上文讲到 springboot 的自动装配,本文来记录下 aop 的学习:
个人粗浅认为 springboot 的 aop 功能是利用递归+数组+动态代理+扩张接口来实现的:
先来写一个简单的实现版:
在这里插入图片描述
1,接口:BaseAdvice
在这里插入图片描述
2.前置增强:
在这里插入图片描述
3.后置增强:
在这里插入图片描述
3.责任链的类:
在这里插入图片描述
3.测试类:
在这里插入图片描述
执行的打印结果:
在这里插入图片描述
现在来说明:
在这里插入图片描述
Chain类 封装了增强类 ADVICE 的集合,ADVICE 在执行增强方法的时候存储了形参 Chain的实现类,在Chain 调用 proceed 方法时实际上就是调用了装载在增强类结合的对象,接着按照增强的类型来选择执行调用增强方法与调用 Chain 的 proceed 方法,一次来形成递归的调用,在Chain 封装了执行次数,与当前的集合的长度做比较,如果等于当前的长度,则表示现在应该执行目标方法,接着按照调用的增强类的逆序返回;spring 的 aop 也是基于这种方式来完成的,chain 就是代表封装了增强方法的几个,递归调用其中的增强类,执行目标方法,最后逆序返回调用;
springboot 的aop也是基于自动装配功能来的,看注解:
在这里插入图片描述
看:在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里很明显了,AspectJAutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar 接口,在spring 加载bean的定义时,会调用这个方法,将这个 org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator 的类信息加载到上下文,那么这个到底是是什么时候开始调用的,看继承关系:
在这里插入图片描述
明白了,猜想要么就是在实话之前调用,要么实例化之后调用,动态代理是对原目标类的增强的,也就是说必须有目标对象,所以应该是在实例化之后调用的,断点:
在这里插入图片描述
在这里插入图片描述
到实例化之前调用,实例化后调用之前还不是代理类,答案明显了:
在这里插入图片描述接着:

	public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = this.aspectBeanNames;

		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					List<Advisor> advisors = new ArrayList<>();
					aspectNames = new ArrayList<>();
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					for (String beanName : beanNames) {
						if (!isEligibleBean(beanName)) {
							continue;
						}
						// We must be careful not to instantiate beans eagerly as in this case they
						// would be cached by the Spring container but would not have been weaved.
						Class<?> beanType = this.beanFactory.getType(beanName);
						if (beanType == null) {
							continue;
						}
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								if (this.beanFactory.isSingleton(beanName)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								advisors.addAll(classAdvisors);
							}
							else {
								// Per target or per this.
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name '" + beanName +
											"' is a singleton, but aspect instantiation model is not singleton");
								}
								MetadataAwareAspectInstanceFactory factory =
										new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
								this.aspectFactoryCache.put(beanName, factory);
								advisors.addAll(this.advisorFactory.getAdvisors(factory));
							}
						}
					}
					this.aspectBeanNames = aspectNames;
					return advisors;
				}
			}
		}

		if (aspectNames.isEmpty()) {
			return Collections.emptyList();
		}
		List<Advisor> advisors = new ArrayList<>();
		for (String aspectName : aspectNames) {
			List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
			if (cachedAdvisors != null) {
				advisors.addAll(cachedAdvisors);
			}
			else {
				MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
				advisors.addAll(this.advisorFactory.getAdvisors(factory));
			}
		}
		return advisors;
	}

这个方法非常关键的,在getBean 的时候,会通过 CreateBean 然后调用:
在这里插入图片描述这里最终会调用以上的 buildAspectJAdvisors 方法代码,整体思路就是通过循环加载到的beannames,beanFactory.getType(name) 获取对象的Class ,判断上面有没有@Aspect 注解,有则封装成包装增强类来存储,等到下次用,需要注意的是只要开启了增强的功能,每一个 bean 的创建都会调用到 ,因为BBP是参与到所有的Bean 的生命周期的,
在这里插入图片描述
只不过在后面判断条件为否而已;回到:
在这里插入图片描述
返回的对象时封装了增强类,这里并没有对增强类里面的前后置增强进行排序之类的;接着:
在这里插入图片描述
在这里就又将 specificInterceptors 数组封装成 advisors 数组,没搞懂,略过,感觉主要是创建 proxyFactory 对象,并设定参数而已,
基往下走:
在这里插入图片描述
在这里开始看到判断是进行哪一种代理方式:主要是判断是不是接口的方式,如果是的话则走 jdk ,否则就是cglib, 此处例子是 cglib ,
在这里插入图片描述所以最终返回得是
在这里插入图片描述
此时并没有创建责任链,在调用的时候创建。断点进去:
在这里插入图片描述
首先是获取对应的目标类以及Class,接着就是获取责任链了:
在这里插入图片描述
接着就是调用了:
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
在这里插入图片描述
到此基本脉络大概清楚了:
springboot 的 aop 功能是建立在动态代理+注解+扩招接口+责任链+递归的基础上完成的,首先通过

  1. 启动注解 @EnableAspectJAutoProxy
  2. @Import(AspectJAutoProxyRegistrar.class)
  3. 通过 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry) 注册定义:
    AnnotationAwareAspectJAutoProxyCreator.class 实现:SmartInstantiationAwareBeanPostProcessor
    在调用 getBean 创建对象的时候,先创建对象,具体过程参考
    学习笔记—spring bean的生命周期的简单分析 在初始化之后调用:
    postProcessAfterInitialization 方法,获取增强类,判断执行何种代理方式,返回代理对象;
    在调用的时候则创建责任链,根据责任链的长度递归调用增强方法,最后执行 目标方法,类以及参数的信息 返回结果;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值