Spring Aop 执行流程

闲聊

在Spring Bean的生命周期中,处理aop的流程只有第一步处理通知和最后一步创建代理对象。

可以说只要去掉第一步和最后一步,也不会影响SpringBean的生命周期。可见在生命周期中处理aop 和aop的理念是完全符合解耦的思想。

切面的组成

一个简单的切面AspectJ 通常可以由多个切入点Pointcut 和多个通知Advice 组成。

切入点:切入点和切入点表达式相辅相成的存在,通常由切入点表达式决定切入点需要切入的位置

通知:在切面里面,通知通常分为五种。分别是前置通知,环绕通知,后置通知,异常通知和返回通知。

类图

类图分析

五种通知都继承了一个抽象的父类  AbstractAspectJAdvice,通知的顶级接口 Advice

AspectJMethodBeforeAdvice 实现了 MethodBeforeAdvice ,MethodBeforeAdvice又继承了 BeforeAdvice

AspectJAfterReturningAdvice 实现了 AfterReturningAdvice,AfterReturningAdvice又继承了 AfterAdvice

AspectJAfter......类型的通知实现了AfterAdvice 接口

而另外的三个通知  AspectJAroundAdvice, AspectJAfterAdvice ,AspectJAfterThrowingAdvice 有一个共同实现 MethodInterceptor 这是一个拦截器

 调用通知的逻辑是一个Interceptor的递归调用链,但是AspectJMethodBeforeAdvice 和 AspectJAfterReturningAdvice并不是一个拦截器。

所以会有 AspectJMethodBeforeAdvice 通过 MethodBeforeAdviceAdapter  变成一个 MethodBeforeAdviceInterceptor

AspectJAfterReturningAdvice 通过 AfterReturningAdviceAdapter 变成一个 AfterReturningAdviceInterceptor

如何处理通知

Spring Bean 的生命周期中第一步是如何处理通知的呢。

一个切点 == Pointcut , 一个通知 == advice,而一个切面 == List<Advisor>

 一个切面里面有几个通知最后都会封装成几个advisor,advisor里面的 pointcut可能一样。

生成 advisor 流程

1.Spring Bean 生命周期第一步

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

2.获取所有被@Aspect 注解标记的beanName 循环生成List<Advisor>,在统一放入一个大的List<Advisor> 集合中。通过缓存控制避免重复解析。

3.通过beanName 和 beanFactory 封装该切面对应的通知工厂,通过通知工厂产生对应的通知,在封装到集合中去

4.生成不同类型的advisor 。InstantiationModelAwarePointcutAdvisorImpl 一个advisor接口的实现类。从工厂中获取到(创建)的advisor,都会放到InstantiationModelAwarePointcutAdvisorImpl 的 Advice instantiatedAdvice 属性中 。

	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;
		this.aspectJAdvisorFactory = aspectJAdvisorFactory;
		this.aspectInstanceFactory = aspectInstanceFactory;
		this.declarationOrder = declarationOrder;
		this.aspectName = aspectName;

		if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			// Static part of the pointcut is a lazy type.
			Pointcut preInstantiationPointcut = Pointcuts.union(
					aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

			// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
			// If it's not a dynamic pointcut, it may be optimized out
			// by the Spring AOP infrastructure after the first evaluation.
			this.pointcut = new PerTargetInstantiationModelPointcut(
					this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
			this.lazy = true;
		}
		else {
			// A singleton aspect.
			this.pointcut = this.declaredPointcut;
			this.lazy = false;
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
	}

构造方法里面包含了一整个切面的信息。再看 instantiateAdvice(this.declaredPointcut) 里面的getAdvisor 方法

	public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);

		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		// If we get here, we know we have an AspectJ method.
		// Check that it's an AspectJ-annotated class
		if (!isAspect(candidateAspectClass)) {
			throw new AopConfigException("Advice must be declared inside an aspect type: " +
					"Offending method '" + candidateAdviceMethod + "' in class [" +
					candidateAspectClass.getName() + "]");
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Found AspectJ method: " + candidateAdviceMethod);
		}

		AbstractAspectJAdvice springAdvice;

		switch (aspectJAnnotation.getAnnotationType()) {
			case AtPointcut:
				if (logger.isDebugEnabled()) {
					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
				}
				return null;
			case AtAround:
				springAdvice = new AspectJAroundAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtBefore:
				springAdvice = new AspectJMethodBeforeAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfter:
				springAdvice = new AspectJAfterAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfterReturning:
				springAdvice = new AspectJAfterReturningAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterReturningAnnotation.returning())) {
					springAdvice.setReturningName(afterReturningAnnotation.returning());
				}
				break;
			case AtAfterThrowing:
				springAdvice = new AspectJAfterThrowingAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
					springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
				}
				break;
			default:
				throw new UnsupportedOperationException(
						"Unsupported advice type on method: " + candidateAdviceMethod);
		}

		// Now to configure the advice...
		springAdvice.setAspectName(aspectName);
		springAdvice.setDeclarationOrder(declarationOrder);
		String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
		if (argNames != null) {
			springAdvice.setArgumentNamesFromStringArray(argNames);
		}
		springAdvice.calculateArgumentBindings();

		return springAdvice;
	}

最终通过不同通知的类型生成不同的advisor 并返回。

绑定通知并生成代理对象

Spring Bean生命周期中的最后一步将切面对象与通知进行绑定。

绑定通知

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

进行到这一步的时候这个bean已经被实例化出来了。

绑定通知流程其实在上篇解析表达式的时候就已经出来了。

循环每一个advisor 。通过表达式 和 bean.getClass() 去两次匹配

	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}
	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}
	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}

第一次 canApply(candidate, clazz) 匹配 进去 hasIntroductions == false,也会两次匹配,第一次匹配类型,在循环方法 再次匹配,第一次基本就可以实现命中目标方法,当在每个通知里面循环完该对象的方法时,就已经完成绑定了。

第二次 canApply(candidate, clazz, hasIntroductions) hasIntroductions == true 再次匹配,能进入到再次匹配,是直接返回true 的,代表命中了。

创建代理对象

绑定完通知后会根据对象类型去生成不同的代理对象。比如 jdk动态代理或者cglib动态代理。

但是这一步里面会将advisor 转化成 interceptor 

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

createProxy里面

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

循环绑定的所有通知

for (int i = 0; i < allInterceptors.size(); i++) {
	advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

	private final List<AdvisorAdapter> adapters = new ArrayList<>(3);


	/**
	 * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
	 */
	public DefaultAdvisorAdapterRegistry() {
		registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
		registerAdvisorAdapter(new AfterReturningAdviceAdapter());
		registerAdvisorAdapter(new ThrowsAdviceAdapter());
	}


	@Override
	public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
		if (adviceObject instanceof Advisor) {
			return (Advisor) adviceObject;
		}
		if (!(adviceObject instanceof Advice)) {
			throw new UnknownAdviceTypeException(adviceObject);
		}
		Advice advice = (Advice) adviceObject;
		if (advice instanceof MethodInterceptor) {
			// So well-known it doesn't even need an adapter.
			return new DefaultPointcutAdvisor(advice);
		}
		for (AdvisorAdapter adapter : this.adapters) {
			// Check that it is supported.
			if (adapter.supportsAdvice(advice)) {
				return new DefaultPointcutAdvisor(advice);
			}
		}
		throw new UnknownAdviceTypeException(advice);
	}

	@Override
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		Advice advice = advisor.getAdvice();
		if (advice instanceof MethodInterceptor) {
			interceptors.add((MethodInterceptor) advice);
		}
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[0]);
	}

	@Override
	public void registerAdvisorAdapter(AdvisorAdapter adapter) {
		this.adapters.add(adapter);
	}

}

wrap 方法里面

advice instanceof MethodInterceptor 处理AspectJAroundAdvice, AspectJAfterAdvice ,AspectJAfterThrowingAdvice 三种类型。

AdvisorAdapter adapter : this.adapters 通过策略处理AspectJMethodBeforeAdvice 和 AspectJAfterReturningAdvice 这两种类型。

执行方法,调用责任链

执行方法

当我们执行目标方法的时候,会进入到代理类的invoke方法里面去,在这个方法里面对根据方法去匹配生成好的责任链通知。

1.被执行的这个目标方法是否被通知织入了需要增强的方法。

即使目标对象里面的某一个方法被增强的,这个目标对象还是依然会被生成代理对象,不管执行该目标对象的哪一个方法,都会进入代理对象的invoke方法。如果是jdk动态代理生成的代理对象,进入invoke里面的目标方法是一个抽象的方法,需要转化,而cglib动态代理生成的代理对象进入intercepter 的不是抽象的。

2.匹配责任链通知 还会进行 上文类似的canApply(candidate, clazz) 匹配,具体看jdk 和cglib执行的逻辑大致相同。

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
	@Override
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;

		for (Advisor advisor : advisors) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						match = mm.matches(method, actualClass);
					}
					if (match) {
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

简化一下代码,自己写的。匹配规则是一样的,先匹配class,再匹配method,然后返回一个结果集 List<Object> chain

    private List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method) {
        List<XxAdvisor> advisors = this.advisors;
        for (XxAdvisor advisor : advisors) {
            if(advisor instanceof XxPointcutAdvisor){
                XxPointcutAdvisor pointcutAdvisor = (XxPointcutAdvisor) advisor;
                if(pointcutAdvisor.getXxPointcut().getXxClassFilter().matches(this.target.getClass())){
                    XxMethodMatcher xxMethodMatcher = pointcutAdvisor.getXxPointcut().getXxMethodMatcher();
                    boolean match = false;
                    if(xxMethodMatcher instanceof XxIntroductionAwareMethodMatcher){
                        match = (xxMethodMatcher).matches(method, this.target.getClass());
                    }
                    if(match){
                        interceptorList.addAll(Arrays.asList(getInterceptors(advisor)));
                    }
                }
            }
        }
        return interceptorList;
    }

递归调用责任链

jdk动态代理的invoke 责任链调用

invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();

cglib动态代理的interceptor责任链调用

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

new 出来的对象都是一个MethodInvocation类型的方法调用对象

重点看 proceed 方法,两种类型创建出来的对象执行 proceed方法是同一段代码块

	public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

简化一下就是这样的,自己写的

public Object proceed() throws Throwable {
    if(this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()-1){
        return this.method.invoke(this.target,this.arguments);
    }
    Object interceptorOrInterceptionAdvice =
               this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    return ((XxMethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}

每次进来都只会执行最后一个return里面的逻辑。当执行到最后一个interceptor 的时候,就执行第一个return里面的逻辑。

每次执行最后的return逻辑的时候,对应的都是不同通知的拦截器,每个拦截器会匹配进入不同类型的通知(因为每个通知已经是一个拦截器了)里面的逻辑,当执行完不同通知的逻辑会再次调用父类里面的方法,而父类里面的方法最终返回的是当前目标方法的invoke方法,所以又递归回来了。

又回到了该方法的起点。

自己仿Spring Aop 写的这个责任链的递归调用也没整明白这种调用模式..........

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值