springAop原理之(五)创建代理bean及其代理bean方法具体执行过程

6 篇文章 0 订阅

目录

代理bean生成

查找代理方法相关的Advisor

代理方法执行流程


上一篇文章springAop原理之查找和原始bean关联的Advisor.已经分析了spring如何查找和判断Advisor是否和原始Bean关联,这里接着继续讲spring是如何根据这些Advisor创建代理bean及其代理bean方法具体执行过程

代理bean生成

AbstractAutoProxyCreator#wrapIfNecessary部分源码。可以看到将当前原始bean包装成SingletonTargetSource类型

// Create proxy if we have advice.
//获取bean有关的Advisor
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方法,中间跳过,可以看到将包装后的bean和advisor添加到ProxyFatory中,也就是advised(ProxyFatory父类)中。下面都已advised代替ProxyFactory,继续往下

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

		ProxyFactory proxyFactory = new ProxyFactory();
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		return proxyFactory.getProxy(getProxyClassLoader());
	}

getProxy: createAopProxy()返回的就是基于基于JDK的JdkDynamicAopProxy或基于CGLIBObjenesisCglibAopProxy,这里就不深入看了。

	public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}

我们以JdkDynamicAopProxy为例分析getProxy方法。
记住在上面生成JdkDynamicAopProxy过程中,会将当前包含原始bean的包装类和advisor的advised赋值到JdkDynamicAopProxy属性AdvisedSupport advised中

	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

最后一行代码就很熟悉了。我们知道jdk动态代理是需要一个InvocationHandler的实现类的,真正执行方法时是会执行InvocationHandler中的invoke方法。会发现JdkDynamicAopProxy自身就实现了该接口,所以后续代理对象方法的执行都是通过执行JdkDynamicAopProxy的invoke方法来触发的。

查找代理方法相关的Advisor

一开查找原始bean有关的advisor只是为了判断是否需要代理。但并不是说这些advisor会关联该bean的所有方法。以事务注解@Transactional为例来说,只有方法上由这个注解的(不考虑类上的)才会执行相应的切面逻辑,没有的则直接走原始bean的具体方法。所以这里就需要具体分析下JdkDynamicAopProxy中invoke方法。上面已经阐述了原理,这里直接分析源码。

简化版源码:

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //1
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
			if (chain.isEmpty()) {
                //2
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
                //3
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				retVal = invocation.proceed();
			}
			return retVal;
		}
	}
  • 代码中1处这句就是获取和方法相关的Advisor中的Advice,在spring中就是MethodInterceptor

            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

 我们知道advised中包含了原始bean的包装类和所有的advisor。该方法最终会调用DefaultAdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法,该方法有些长,这里简单说下原理。

原理就是通过Advisor中的pointcut的ClassFilter和MethodMatcher 进行匹配,匹配结果为true的话,调用DefaultAdvisorAdapterRegistry的getInterceptors方法,将Advisor中的Advice包装成MethodInterceptor返回

所以最终上面的chain数组变量指向的就是和当前方法有关的所有Advice。

  • 代码2处就是如果没有与当前方法相关的Advice,则直接反射执行原始bean的该方法
  • 代码3处就是真正执行切面逻辑的。可以看到时委托给了ReflectiveMethodInvocation去执行,下面就具体分析下执行流程

代理方法执行流程

ReflectiveMethodInvocation采用责任链模式,依次执行每一个MethodInterceptor。

简化版的proceed方法。

interceptorsAndDynamicMethodMatchers就是传进来的Advice数组。

  1. 从数组第一个MethodInterceptor(MethodInterceptor代替Advice说明)开始执行其invoke方法。我们知道invoke方法是需要一个MethodInvocation类型的参数,而ReflectiveMethodInvocation就实现了该接口,所以将自身传了进去。
  2. MethodInvocation就是一种方法基本的链接点,所以MethodInterceptor的invoke方法最后必须执行MethodInvocation的proceed方法以执行具体的原始方法逻辑,或通过MethodInvocation的getMethod方法获取到原始方法并反射执行原始方法逻辑,
    ,不然原始的方法就不能够执行。这里只讨论proceed方法。所有的切面逻辑其实都是在执行proceed方法之前完成的。
  3. ReflectiveMethodInvocation的proceed方法又回到了第一步,接着获取第二个Advice来执行。如此循环就会执行完所有的advice。proceed方法开头的判断就是如果执行完了所有的advice,就执行invokeJoinpoint方法,也就时通过反射执行原始bean的原始方法。
	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);
		// 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);
	}

这里有一点非常重要也很容易忽视。那就是最后通过反射执行原始方法的返回值并不是直接返给

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

上面代码的 ,而是返给上一个MethodInterceptor的,第一个MethodInterceptor的invoke方法的返回值才是返给上述代码的。也就是说如果再不改变原始方法的返回值的情况下,原始的返回值会倒叙一层一层往上返回。

为啥要说这一点呢,因为很重要。比如以事务相关的TransactionInterceptor来说,它的invoke方法会调用父类TransactionAspectSupport的invokeWithinTransaction方法,下方为部分源码。正是通过此方法开启事务/提交事务/回滚事务。下方代码1处就可以获取到原始方法返回值。发生异常回滚,正常则提交事务。

			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				// This is an around advice: Invoke the next interceptor in the chain.
				// This will normally result in a target object being invoked.
                //1
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// target invocation exception
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值