SpringAop源码情操陶冶-JdkDynamicAopProxy
2017-11-12 16:33
441 查看
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思想。
小结
AOP代理主要是获取对应bean的beanClass绑定的
Advice集合,而此集合类似于拦截器
针对拦截器的遍历,AOP是采用了递归的思想来遍历
ReflectiveMethodInvocation#proceed()方法来实现
而对相同类型的
Advice,比如
AspectJAfterAdvice,有无执行的先后顺序,读者可自行查阅
相关文章推荐
- SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator
- Spring源码情操陶冶-AOP之ConfigBeanDefinitionParser解析器
- Spring的代理模式及Spring AOP-JDKDynamicAopProxy
- Spring源码情操陶冶-AOP之Advice通知类解析与使用
- Spring源码-AOP(二)-jdkProxy与cglib
- Spring源码情操陶冶-PropertyPlaceholderBeanDefinitionParser注解配置解析器
- Spring源码情操陶冶-AbstractApplicationContext#invokeBeanFactoryPostProcessors
- Spring源码情操陶冶-AbstractApplicationContext#obtainFreshBeanFactory
- Spring源码-AOP(五)-ProxyFactoryBean
- ITCAST视频-Spring学习笔记(使用JDK中的Proxy技术实现AOP功能)
- Spring源码情操陶冶-DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
- Spring源码情操陶冶-自定义节点的解析
- Spring源码情操陶冶-AbstractApplicationContext#onRefresh
- Spring源码情操陶冶-PathMatchingResourcePatternResolver路径资源匹配溶解器
- 15_传智播客Spring2.5视频教程_使用JDK中的Proxy技术实现AOP功能
- Spring源码情操陶冶-AbstractApplicationContext
- Spring源码分析之ProxyFactoryBean方式实现Aop功能的分析
- Spring源码情操陶冶-任务定时器ConcurrentTaskScheduler
- Spring源码情操陶冶-AbstractApplicationContext#prepareRefresh
- 浅析Spring AOP源码(十三) jdk的动态代理和cglib的代理