zoukankan      html  css  js  c++  java
  • SpringAop源码情操陶冶-JdkDynamicAopProxy

    承接前文SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator,本文在前文的基础上稍微简单的分析默认情况下的AOP代理,即JDK静态代理

    JdkDynamicAopProxy#getProxy()-获取代理对象

    首先我们先看下JDK代理是如何创建代理对象的,直接端上源码

    @Override
    	public Object getProxy(ClassLoader classLoader) {
    		if (logger.isDebugEnabled()) {
    			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
    		}
    		// 获取指定beanClass上的所有接口
    		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
    		// 简单查询下代理的接口有无定义了equals和hashCode方法
    		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    		// 熟悉的套路以及配方
    		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    	}
    

    上述源码还是很简单的对需要代理的接口进行获取并创建我们熟知的JDK代理

    JdkDynamicAopProxy#invoke()-拦截相应的接口方法

    我们直接切入JDK代理的直接调用方法invoke(),端上源码

    /**
    	 * Implementation of {@code InvocationHandler.invoke}.
    	 * <p>Callers will see exactly the exception thrown by the target,
    	 * unless a hook method throws an exception.
    	 */
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		MethodInvocation invocation;
    		Object oldProxy = null;
    		boolean setProxyContext = false;
    
    		TargetSource targetSource = this.advised.targetSource;
    		Class<?> targetClass = null;
    		Object target = null;
    
    		try {
    			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
    				// The target does not implement the equals(Object) method itself.
    				return equals(args[0]);
    			}
    			if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
    				// The target does not implement the hashCode() method itself.
    				return hashCode();
    			}
    			if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
    					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
    				// Service invocations on ProxyConfig with the proxy config...
    				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    			}
    
    			Object retVal;
    			// 以上部分的源码我们可以不用关注,我们关注点从这往下
    			if (this.advised.exposeProxy) {
    				// Make invocation available if necessary.
    				oldProxy = AopContext.setCurrentProxy(proxy);
    				setProxyContext = true;
    			}
    
    			// May be null. Get as late as possible to minimize the time we "own" the target,
    			// in case it comes from a pool.
    			target = targetSource.getTarget();
    			if (target != null) {
    				targetClass = target.getClass();
    			}
    
    			// Get the interception chain for this method.
    			// 关注点1,获取Advice集合,类似于拦截器的概念
    			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
    			// Check whether we have any advice. If we don't, we can fallback on direct
    			// reflective invocation of the target, and avoid creating a MethodInvocation.
    			if (chain.isEmpty()) {
    				// 拦截器为空则直接调用方法
    				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
    			}
    			else {
    				// We need to create a method invocation...
    				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    				// Proceed to the joinpoint through the interceptor chain.
    				// 关注点2,使用ReflectiveMethodInvocation来返回具体对象
    				retVal = invocation.proceed();
    			}
    
    			// Massage return value if necessary.
    			// 以下我们也可以忽略
    			Class<?> returnType = method.getReturnType();
    			if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
    					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
    				// Special case: it returned "this" and the return type of the method
    				// is type-compatible. Note that we can't help if the target sets
    				// a reference to itself in another returned object.
    				retVal = proxy;
    			}
    			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
    				throw new AopInvocationException(
    						"Null return value from advice does not match primitive return type for: " + method);
    			}
    			return retVal;
    		}
    		finally {
    			// 判断是否需要释放资源
    			if (target != null && !targetSource.isStatic()) {
    				// Must have come from TargetSource.
    				targetSource.releaseTarget(target);
    			}
    			if (setProxyContext) {
    				// Restore old proxy.
    				AopContext.setCurrentProxy(oldProxy);
    			}
    		}
    	}
    

    上述的源码内容过多,我们可以省略掉一些细则的代码,直接查看其关键的代码,针对上面的标注,我们主要关注两点:

    • AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice()获取Advise集合,也就是类似于拦截器集合
    • ReflectiveMethodInvocation#proceed()根据上述的拦截器集合,执行真正的代理逻辑

    AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice()-获取拦截器集合

    里面的代码涉及了简单的缓存,为了节省用餐时间,我们直接去看关键类的关键方法DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice(),直接上菜

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    			Advised config, Method method, Class<?> targetClass) {
    
    		// This is somewhat tricky... We have to process introductions first,
    		// but we need to preserve order in the ultimate list.
    		List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
    		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    		boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    		// 遍历bean工厂中已创建的Advisor集合
    		for (Advisor advisor : config.getAdvisors()) {
    			if (advisor instanceof PointcutAdvisor) {
    				// Add it conditionally.
    				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
    				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
    					MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
    					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
    					if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
    						if (mm.isRuntime()) {
    							// 创建InterceptorAndDynamicMethodMatcher包装对象
    							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;
    	}
    

    上述的代码认真分析的话比较复杂,简单粗略的看之我们可以得到要么会创建InterceptorAndDynamicMethodMatcher包装对象,要么会直接获取Interceptor对象。前者主要应用在下文的proceed()方法

    ReflectiveMethodInvocation#proceed()-执行真正的代理逻辑

    直接把源码端上

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

    其实到上述这段代码,读者可以稍微关注下,每个MethodInterceptor都会传入this这个对象,如果稍微跟踪下就会发现,其实都是采用try-catch机制,内部会继续调用本类的proceed()方法,类似于递归的思想。而try-catch机制恰好反映了before/after/around等aop思想。

    小结

    1. AOP代理主要是获取对应bean的beanClass绑定的Advice集合,而此集合类似于拦截器

    2. 针对拦截器的遍历,AOP是采用了递归的思想来遍历ReflectiveMethodInvocation#proceed()方法来实现

    3. 而对相同类型的Advice,比如AspectJAfterAdvice,有无执行的先后顺序,读者可自行查阅

  • 相关阅读:
    20170417列表的count计数、index、reverse、sort函数
    (一)grpc-创建一个简单的grpc 客户端和服务器
    通用装饰器
    Git学习(一):Git介绍、仓库和分支等基本概念解释
    APP测试
    接口测试用例设计
    笔记整理
    接口测试
    gzip -压缩与解压缩
    declare 命令 -声明shell 变量
  • 原文地址:https://www.cnblogs.com/question-sky/p/7821958.html
Copyright © 2011-2022 走看看