【Spring源码】三:AOP执行过程

什么是AOP

AOP是不同于OOP的一种编程思想,AOP关注的是横向,OOP关注的是纵向
将系统中与业务无关的动作或服务(如:日志记录、事务处理、权限控制)设计为通用、不介入特定业务对象的、职责清楚的Aspect对象,这就是Aspect-oriented programming,即AOP编程
在这里插入图片描述

  • Aspect:使用代理对象将记录等与业务无关的动作或任务提出来,设计为一个服务对象,这样的对象称为切面
  • Advice:Aspect指的是一类服务,而Advice是这类服务当中具体的一个,如日志服务前面的DynamicProxy类 (Advice与Aspect是具体与抽象的关系)
  • Pointcut(切入点):Pointcut是一个定义,可以由它定义一些织入时机(Joinpoint)
  • Joinpoint(织入时机,连接点):在业务流程执行时织入Aspect对象的时机,如业务方法执行之前、之后、异常发生时
  • Cross-cutting-concern:StudentService本身的职责添加学生,却必须插入日志记录这样的与业务无关的动作,这样的动作AOP中称为横切关切点(Cross-cutting-concern)

创建过程

在这里插入图片描述

创建代理之前需要,一些准备工作,设置拦截器,设置父类,设置回调

  1. 设置拦截器,这里通过切入表达式来匹配需要的Advisor,筛选完仅需拓扑排序就是成为了这个类所需要的Advisor,设置进拦截器链 (Aspect到Advisor解析过程 是在第一次调用findcandidateadvisor解析出来的,后面匹配过程直接使用,注意的是不同方法可能使用的拦截器链不同)

resolveBeforeInstantiation -> applyBeanPostProcessorsBeforeInstantiation ->postProcessBeforeInstantiation
判断逻辑

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;
	}
}

isInfrastructureClass:判断当前是否是spring自己需要的系统内部类(是否为Advice,Pointcut,Advisor…)
shouldSkip:判断当前类是否需要被被代理,判断就需要找到所有的advisor来判定,所以第一次调用这个方法就会把所有的advisor创建出来。是通过类型把容器及其父容器的advisorName取出来,下面就是取出来的Name结果

advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
	// TODO: Consider optimization by caching the list of the aspect names
	//获取advisor
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	//advisor和aspect无需代理
	for (Advisor advisor : candidateAdvisors) {
		if (advisor instanceof AspectJPointcutAdvisor &&
				((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
			return true;
		}
	}
	return super.shouldSkip(beanClass, beanName);
}

在这里插入图片描述

AspectJPointcutAdvisor#0 虽然是相同的前缀,但是# 后数字不同执行的对象是不同的,比如#0指向的是AspectJAround

得到Name自然可以getBean来实例化

advisors.add(this.beanFactory.getBean(name, Advisor.class));

一般是调用无参构造来创建对象,后面属性填充来填充属性
但这些Advisor没有无参,调用的有参构造,所以需要把构造器中需要的对象提前创建好。

在这里插入图片描述

public AspectJAroundAdvice(
		Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
	super(aspectJAroundAdviceMethod, pointcut, aif);
}

所以创建过程会设计Method AspectJExpressionPointcut AspectInstanceFactory

创建advisor符合 isInfrastructureClass,不会被创建代理,所以被放入了advisedBeans

  1. 设置父类,setSuperclass很简单
  2. 设置回调,将七个回调传入,主要是DynamicAdviceInterceptor里面属性会设置拦截器链

准备完成之后就可以创建代理,之后调用函数就是调用代理对象的函数(因为一级缓存,缓存的是这个代理对象了)

下面拿了部分代码,不是存在与同一个方法中

//获取拦截器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
//会把拦截器变为advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//设置父类
enhancer.setSuperclass(proxySuperClass);
//得到回调,并且getCallbacks会把advisor放入DynamicAdviceInterceptor中
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
	types[x] = callbacks[x].getClass();
}
//设置回调
enhancer.setCallbackTypes(types);

调用过程

在这里插入图片描述

调用add方法,是调用代理的add方法,代理的add方法是调用回调里面DynamicAdviceInterceptor的interceptor方法

在这里插入图片描述

这个interceptor方法或获取这个方法对应的拦截器链,然后需要转换为MethodInterceptor,其中有几个本身是MethodInterceptor子类,另外的比如AspectJAfterReturningAdvice和AspectJMethodBeforeAdvice不是MethodInterceptor子类需要由adapter帮助转换
有了拦截器链,同对象,方法一起传入CglibMethodInvocation,调用proceed方法

new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed()

在这里插入图片描述
整个调用过程是CglibMethodInvocation和拦截器链配合调用,效果就和上面的图差不多,执行过程一句话说不清

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yilyil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值