引
在前面的两节,通过分析shouldSkip方法,已经完成了SpringAOP中增强(切面)的创建,并将获取到的切面进行缓存,接下来继续分析SpringAOP创建代理的过程。即AbstractAutoProxyCreator类的postProcessAfterInitialization方法。
/** * 如果bean被子类标识为要代理的bean,则使用配置的拦截器创建代理。 * Create a proxy with the configured interceptors if the bean is * identified as one to proxy by the subclass. * @see #getAdvicesAndAdvisorsForBean */ @Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { // 为beanName和beanClass构建缓存key Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { // 包装bean return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
创建代理过程发生在wrapIfNecessary方法里,打开该方法:
/** * 如果需要则包装该bean,例如该bean可以被代理 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied. * @param bean the raw bean instance * @param beanName the name of the bean * @param cacheKey the cache key for metadata access * @return a proxy wrapping the bean, or the raw bean instance as-is */ protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 1、如果已经处理过或者不需要创建代理,则返回 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // 2、创建代理 // 2.1 根据指定的bean获取所有的适合该bean的增强 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { // 2.2 为指定bean创建代理 this.advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } // 3、缓存 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
创建代理的过程发生在第二步,先得到适合当前bean的增强,然后再根据得到的增强创建代理。下面逐个分析:
1. 根据指定的bean获取所有的适合该bean的增强流程简析
/** * 获取指定bean的增强 * @param beanClass the class of the bean to advise * @param beanName the name of the bean * @param targetSource * @return */ @Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); // 如果获取到的增强是个空的集合,则返回DO_NOT_PROXY-->空数组 if (advisors.isEmpty()) { return DO_NOT_PROXY; } // 将获取到的增强转换为数组并返回 return advisors.toArray(); }
/** * 为当前bean获取所有需要自动代理的增强 * Find all eligible Advisors for auto-proxying this class. * @param beanClass the clazz to find advisors for * @param beanName the name of the currently proxied bean * @return the empty List, not {@code null}, * if there are no pointcuts or interceptors * @see #findCandidateAdvisors * @see #sortAdvisors * @see #extendAdvisors */ protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { // 1、查找所有候选增强 List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 2、从所有增强集合中查找适合当前bean的增强 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // 3、在eligibleAdvisors集合首位加入ExposeInvocationInterceptor增强 extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
流程非常的简单,先的到所有的增强,再从所有增强中找到适合当前bean的增强。其中获取所有增强的过程,已经在前两个章节分析过,这里不再赘述,来看Spring是如何从所有增强中找到适合当前bean的增强的。
3. 从增强集合中找到适合当前bean的增强
/** * 从给定的增强中找出可以应用到当前指定bean的增强 * Search the given candidate Advisors to find all Advisors that * can apply to the specified bean. * @param candidateAdvisors the candidate Advisors * @param beanClass the target's bean class * @param beanName the target's bean name * @return the List of applicable Advisors * @see ProxyCreationContext#getCurrentProxiedBeanName() */ protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); } }
该工作委托给了AopUtils类的findAdvisorsThatCanApply方法。
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { // 1、候选增强为空,直接放回 if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } // 2、处理引介增强 List<Advisor> eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } // 2、处理普通增强 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方法判断,并将符合条件的增强加入到Advisor集合中返回即可。那么接下来就该分析canApply方法了。
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { // 1、处理引介增强 if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } // 2、处理普通增强 else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. return true; } }
在该方法中又出现了引介增强和普通增强,我们还是只看普通增强的判断过程:
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { // 1、判断类是否匹配,如类一级别不匹配,直接返回false if (!pc.getClassFilter().matches(targetClass)) { return false; } // 2、判断如果当前Advisor所指代的方法的切点表达式如果是对任意方法都放行,直接返回true MethodMatcher methodMatcher = pc.getMethodMatcher(); if (methodMatcher == MethodMatcher.TRUE) { // No need to iterate the methods if we're matching any method anyway... return true; } // 3、尝试将methodMatcher转换为IntroductionAwareMethodMatcher,以提高匹配效率 IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } // 4、获取代理目标的所有接口和实现类 Set<Class<?>> classes = new LinkedHashSet<>(); if (!Proxy.isProxyClass(targetClass)) { classes.add(ClassUtils.getUserClass(targetClass)); } classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); // 5、循环代理目标的所有接口和实现类的所有方法并调用matches方法做匹配判断 for (Class<?> clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); for (Method method : methods) { if (introductionAwareMethodMatcher != null ? // 如果上一步得到的introductionAwareMethodMatcher对象不为空,则使用该对象的matches匹配 introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : // 否则使用Pointcut的methodMatcher对象做匹配 methodMatcher.matches(method, targetClass)) { return true; } } } return false; }
该方法的主要过程在注释里已经分析的很清楚,关键看一下方法匹配过程的处理。
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)
和methodMatcher.matches(method, targetClass)
,因为后者需要根据具体的切点来获取MethodMatcher,所以这里我们只分析一下前者的判断过程。
关于IntroductionAwareMethodMatcher其最主要的实现类就是AspectJExpressionPointcut,来看其具体的匹配过程。
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) { // 1.检查切点表达式,并缓存 obtainPointcutExpression(); // 2.获取ShadowMatch对象并缓存 shadowMatch不知道怎么翻译比较好,姑且叫模糊匹配吧 ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass); // Special handling for this, target, @this, @target, @annotation // in Spring - we can optimize since we know we have exactly this class, // and there will never be matching subclass at runtime. // 3.永远匹配,如果切入点表达式将匹配 此模糊匹配 的任何连接点(例如,对给定方法的任何调用),则为true。 if (shadowMatch.alwaysMatches()) { return true; } // 4.永远不匹配,如果切入点表达式永远不能匹配此 模糊匹配 的任何连接点(例如,切入点将永远不会匹配对给定方法的调用),则为true。 else if (shadowMatch.neverMatches()) { return false; } // 其他匹配: else { // the maybe case if (hasIntroductions) { return true; } // A match test returned maybe - if there are any subtype sensitive variables // involved in the test (this, target, at_this, at_target, at_annotation) then // we say this is not a match as in Spring there will never be a different // runtime subtype. RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch); return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass)); } }
private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) { // 1.从目标类中找到与method最匹配的方法 Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass); // 如果目标类是一个接口(例如:引介增强) // 尝试为继承的方法构建最特定的接口,也可以考虑子接口匹配,特别是代理类. // 注意:AspectJ只考虑Method.getDeclaringClass() if (targetMethod.getDeclaringClass().isInterface()) { // Try to build the most specific interface possible for inherited methods to be // considered for sub-interface matches as well, in particular for proxy classes. // Note: AspectJ is only going to take Method.getDeclaringClass() into account. // 返回给定类的所有接口,包括由超类实现的接口. Set<Class<?>> ifcs = ClassUtils.getAllInterfacesForClassAsSet(targetClass); if (ifcs.size() > 1) { try { Class<?> compositeInterface = ClassUtils.createCompositeInterface( ClassUtils.toClassArray(ifcs), targetClass.getClassLoader()); targetMethod = ClassUtils.getMostSpecificMethod(targetMethod, compositeInterface); } catch (IllegalArgumentException ex) { // Implemented interfaces probably expose conflicting method signatures... // Proceed with original target method. } } } // 返回方法匹配结果 return getShadowMatch(targetMethod, method); }
private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) { // Avoid lock contention for known Methods through concurrent access... ShadowMatch shadowMatch = this.shadowMatchCache.get(targetMethod); if (shadowMatch == null) { synchronized (this.shadowMatchCache) { // Not found - now check again with full lock... PointcutExpression fallbackExpression = null; shadowMatch = this.shadowMatchCache.get(targetMethod); if (shadowMatch == null) { Method methodToMatch = targetMethod; try { try { // 获取切点表达式,并做匹配判断,结果保存到ShadowMatch对象中 shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch); } catch (ReflectionWorldException ex) { // Failed to introspect target method, probably because it has been loaded // in a special ClassLoader. Let's try the declaring ClassLoader instead... // 如果匹配失败,可能是因为使用了特殊的类加载器,则尝试使用该特殊的类加载器替换掉默认的类加载器 try { // 尝试通过目标类的类加载器获取切点表达式 fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass()); if (fallbackExpression != null) { // 再次尝试方法匹配判断 shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch); } } catch (ReflectionWorldException ex2) { fallbackExpression = null; } } // Proxy.isProxyClass-->当且仅当使用getProxyClass方法或newProxyInstance方法将指定的类动态生成为代理类时,方法才返回true。 if (targetMethod != originalMethod && (shadowMatch == null || (shadowMatch.neverMatches() && Proxy.isProxyClass(targetMethod.getDeclaringClass())))) { // Fall back to the plain original method in case of no resolvable match or a // negative match on a proxy class (which doesn't carry any annotations on its // redeclared methods). //在代理类上没有可解析匹配或负匹配(代理类对其重新声明的方法不带任何注释)的情况下,返回到普通的原始方法。 methodToMatch = originalMethod; try { shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch); } catch (ReflectionWorldException ex) { // Could neither introspect the target class nor the proxy class -> // let's try the original method's declaring class before we give up... // 如果原始方法还是无法做出匹配,那么尝试使用原始方法的类,再次去获取切点表达式,并使用该表达式去匹配 try { fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass()); if (fallbackExpression != null) { shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch); } } catch (ReflectionWorldException ex2) { fallbackExpression = null; } } } } catch (Throwable ex) { // Possibly AspectJ 1.8.10 encountering an invalid signature logger.debug("PointcutExpression matching rejected target method", ex); fallbackExpression = null; } // 如果没有得到匹配结果,则默认封装不匹配到ShadowMatchImpl if (shadowMatch == null) { shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null); } // 如果通过匹配结果无法立即判断当前方法是否与目标方法匹配,就将匹配得到的 // ShadowMatch和回调的ShadowMatch封装到DefensiveShadowMatch中 else if (shadowMatch.maybeMatches() && fallbackExpression != null) { shadowMatch = new DefensiveShadowMatch(shadowMatch, fallbackExpression.matchesMethodExecution(methodToMatch)); } // 缓存结果 this.shadowMatchCache.put(targetMethod, shadowMatch); } } } return shadowMatch; }
这一部分分析的不是很透彻,有些东西我也没搞太清楚,留在以后单独开一篇分析吧,但是分析至此,已经可以获取到适合给定bean的所有增强,接下来就是创建代理了。