Spring源码分析-AOP之JDK动态代理实现

0X01 前提条件

  • 基于XML配置加载bean
  • Spring V4.0.8.RELEASE
  • bean为单例模式
  • 基于JDK动态代理实现,Cglib暂且不表,其实两者大致流程差不多,只不过在生成具体代理对象的时候会有点差异

0X02 实现方法

  要了解Spring AOP的实现原理需要将AnnotationAwareAspectJAutoProxyCreator,bean的创建和bean的方法调用三者联系起来。
AnnotationAwareAspectJAutoProxyCreator是bean的后置处理器,程序中开启了AOP功能的话,会将其注入到应用上下文中。AnnotationAwareAspectJAutoProxyCreator实现了接口SmartInstantiationAwareBeanPostProcessor,在bean工厂创建单例bean的过程中,一般会按以下顺序依次调用它的方法对bean加以处理:
在这里插入图片描述
我们主要关注的是postProcessBeforeInstantiation,postProcessAfterInitialization这两个方法有关,它们和代理对象的创建息息相关。
  先来看postProcessBeforeInstantiation,它的主要作用是判断当前创建的bean是否需要增强,在判断的过程中它会收集bean工厂中实现了Advisor接口的增强器(那些正在创建的增强器它是不会获取的)以及将我们自定义的切面信息重新解析封装成一个个增强器,然后放入到缓存中。
而postProcessAfterInitialization方法就是真正创建代理对象的地方,它通过配置信息判断当前是使用jdk动态代理还是cglib代理来生成代理对象,spring提供了个默认的aop代理工厂DefaultAopProxyFactory来做这件事

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
		Class<?> targetClass = config.getTargetClass();
		if (targetClass == null) {
			throw new AopConfigException("TargetSource cannot determine target class: " +
					"Either an interface or a target is required for proxy creation.");
		}
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

  生成了代理对象会将其与beanName相关联注入到应用上下文中,下面来讲讲实际的方法调用过程,可自行阅读JdkDynamicAopProxy的invoke方法,它才是真正实现那些通知调用的地方。首先会获取当前方法的方法拦截器

	// Get the interception chain for this method.
		//将advisor转换为methodInterceptor 即将增强器里的通知用方法拦截器重新封装下
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

这步其实是将增强器转换为方法拦截器,具体转换方法可查阅DefaultAdvisorAdapterRegistry类的getInterceptors方法

	@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
	List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
	Advice advice = advisor.getAdvice();
	//如果通知是MethodInterceptor实现类则直接放入集合中
	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[interceptors.size()]);
}

上述代码需要联系几个通知注解对应的通知实现类才好理解,以下代码片段摘自类ReflectiveAspectJAdvisorFactory的getAdvice方法

	switch (aspectJAnnotation.getAnnotationType()) {
		case AtBefore:
			springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
			break;
		case AtAfter:
			springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
			break;
		case AtAfterReturning:
			springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
			AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterReturningAnnotation.returning())) {
				springAdvice.setReturningName(afterReturningAnnotation.returning());
			}
			break;
		case AtAfterThrowing:
			springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
			AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
				springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
			}
			break;
		case AtAround:
			springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
			break;

获取到了方法拦截器后,下面就是正式进入相关方法调用:先是使用方法拦截器进行递归调用,最后一次递归调用才真正调用目标对象的方法

@Override
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;
		if (dm.methodMatcher.matches(this.method, this.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);
	}
}

方法拦截器的调用是按照以下通知的顺序执行的
@Around>@Before>@After>@AfterReturn>@AfterThrowing

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值