spring.aop 随笔2 pointcut

0. 天热,空调开与不开都感觉到不舒服

Spring AOP源码(2)—AspectJAwareAdvisorAutoProxyCreator创建代理对象【两万字】

@DeclareParents允许代理目标类上新增自定义的方法

【深入Spring】Aspectj的pointcut的表达式

1. 省略ioc过程,直接快进到AbstractAutoProxyCreator

	// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// step into ...
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

	// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		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;
		}

		// step into ...
		// Create proxy if we have advice.
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

		// 如果返回的拦截器数组非空,那么将为该bean创建代理
		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;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
	@Override
	@Nullable
	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

		// step into ...
		// Eligible:有资格的、匹配上的(Candidate:候选的、有可能的、所有的)
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

2. 从Candidate的advisors中找出Eligible的

	// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 获取到所有候选的advisors
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
	
		// step into ...	
		// 找出其中匹配上的advisors
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

		// 队列头加一个spring自带拦截器ExposeInvocationInterceptor
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			// 对有效的advisors排序
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

	// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply
	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			// step into ...
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}

	// org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply
	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
			// step into ...
			// 下面也调用了canApply()
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		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;
	}

	// org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Advisor, java.lang.Class<?>)
	public static boolean canApply(Advisor advisor, Class<?> targetClass) {
		// step into ...
		// 第三个boolean:hasIntroductions <aop:declare-parents/> 或 @DeclareParents
		// 即该advisor属于IntroductionAdvisor 
		return canApply(advisor, targetClass, false);
	}

	// org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Advisor, java.lang.Class<?>, boolean)
	public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
		else if (advisor instanceof PointcutAdvisor) {
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
			// step into ...
			// 从这里的命名,可以知道——终于我们要联系上pointcut了
			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
		else {
			// It doesn't have a pointcut so we assume it applies.
			return true;
		}
	}

3. PointcutAdvisor的匹配过程

  • MethodMatcher.matches()
	// org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)
	public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");

		// 匹配被增强类
		// step into ...
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}

		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		Set<Class<?>> classes = new LinkedHashSet<>();
		if (!Proxy.isProxyClass(targetClass)) {
			classes.add(ClassUtils.getUserClass(targetClass));
		}
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

		for (Class<?> clazz : classes) {
			// 取出并匹配被增强类的所有方法
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			for (Method method : methods) {
				if (introductionAwareMethodMatcher != null ?
						// step into ...
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}

3.1 匹配类

	// org.springframework.aop.aspectj.AspectJExpressionPointcut#matches(java.lang.Class<?>)
	@Override
	public boolean matches(Class<?> targetClass) {
		PointcutExpression pointcutExpression = obtainPointcutExpression();
		try {
			try {
				// step into ...
				return pointcutExpression.couldMatchJoinPointsInType(targetClass);
			}
			catch (ReflectionWorldException ex) {
				logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
				// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
				PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
				if (fallbackExpression != null) {
					return fallbackExpression.couldMatchJoinPointsInType(targetClass);
				}
			}
		}
		catch (Throwable ex) {
			logger.debug("PointcutExpression matching rejected target class", ex);
		}
		return false;
	}

	// org.aspectj.weaver.internal.tools.PointcutExpressionImpl#couldMatchJoinPointsInType
	public boolean couldMatchJoinPointsInType(Class aClass) {
		ResolvedType matchType = world.resolve(aClass.getName());
		if (matchType.isMissing() && (world instanceof ReflectionWorld)) {
			// Class is a generated class that cannot be 'looked up' via getResource.
			// For example a proxy or lambda.
			// Use the class itself in this case
			matchType = ((ReflectionWorld)world).resolveUsingClass(aClass);
		}
		ReflectionFastMatchInfo info = new ReflectionFastMatchInfo(matchType, null, this.matchContext, world);
		// step into ...
		boolean couldMatch = pointcut.fastMatch(info).maybeTrue();
		if (MATCH_INFO) {
			System.out.println("MATCHINFO: fast match for '" + this.expression + "' against '" + aClass.getName() + "': "
					+ couldMatch);
		}
		return couldMatch;
	}

	// org.aspectj.weaver.patterns.KindedPointcut#fastMatch
	@Override
	public FuzzyBoolean fastMatch(FastMatchInfo info) {
		// info.getKind()==null means all kinds
		if (info.getKind() != null) {
			if (info.getKind() != kind) {
				return FuzzyBoolean.NO;
			}
		}

		// KindedPointcut represents these join points:
		// method-execution/ctor-execution/method-call/ctor-call/field-get/field-set/advice-execution/static-initialization
		// initialization/pre-initialization

		// Check if the global fastmatch flag is on - the flag can be removed (and this made default) once it proves stable!
		if (info.world.optimizedMatching) {

			// For now, just consider MethodExecution and Initialization
			if ((kind == Shadow.MethodExecution || kind == Shadow.Initialization) && info.getKind() == null) {
				boolean fastMatchingOnAspect = info.getType().isAspect();
				// an Aspect may define ITDs, and although our signature declaring type pattern may not match on the
				// aspect, the ITDs may have a different signature as we iterate through the members of the aspect. Let's not
				// try and work through that here and just say MAYBE
				if (fastMatchingOnAspect) {
					return MAYBE;
				}
				// Aim here is to do the same test as is done for signature pattern declaring type pattern matching
				if (this.getSignature().isExactDeclaringTypePattern()) {
					ExactTypePattern typePattern = (ExactTypePattern) this.getSignature().getDeclaringType();
					// Interface checks are more expensive, they could be anywhere...
					ResolvedType patternExactType = typePattern.getResolvedExactType(info.world);
					if (patternExactType.isInterface()) {
						ResolvedType curr = info.getType();
						Iterator<ResolvedType> hierarchyWalker = curr.getHierarchy(true, true);
						boolean found = false;
						while (hierarchyWalker.hasNext()) {
							curr = hierarchyWalker.next();
							if (typePattern.matchesStatically(curr)) {
								found = true;
								break;
							}
						}
						if (!found) {
							return FuzzyBoolean.NO;
						}
					} else if (patternExactType.isClass()) {
						ResolvedType curr = info.getType();
						do {
							if (typePattern.matchesStatically(curr)) {
								break;
							}
							curr = curr.getSuperclass();
						} while (curr != null);
						if (curr == null) {
							return FuzzyBoolean.NO;
						}
					}
				} else if (this.getSignature().getDeclaringType() instanceof AnyWithAnnotationTypePattern) {
					// aim here is to say NO if the annotation is not possible in the hierarchy here
					ResolvedType type = info.getType();
					AnnotationTypePattern annotationTypePattern = ((AnyWithAnnotationTypePattern) getSignature().getDeclaringType())
							.getAnnotationPattern();
					if (annotationTypePattern instanceof ExactAnnotationTypePattern) {
						ExactAnnotationTypePattern exactAnnotationTypePattern = (ExactAnnotationTypePattern) annotationTypePattern;
						if (exactAnnotationTypePattern.getAnnotationValues() == null
								|| exactAnnotationTypePattern.getAnnotationValues().size() == 0) {
							ResolvedType annotationType = exactAnnotationTypePattern.getAnnotationType().resolve(info.world);
							if (type.hasAnnotation(annotationType)) {
								return FuzzyBoolean.MAYBE;
							}
							if (annotationType.isInheritedAnnotation()) {
								// ok - we may be picking it up from further up the hierarchy (but only a super*class*)
								ResolvedType toMatchAgainst = type.getSuperclass();
								boolean found = false;
								while (toMatchAgainst != null) {
									if (toMatchAgainst.hasAnnotation(annotationType)) {
										found = true;
										break;
									}
									toMatchAgainst = toMatchAgainst.getSuperclass();
								}
								if (!found) {
									return FuzzyBoolean.NO;
								}
							} else {
								return FuzzyBoolean.NO;
							}
						}
					}
					// Optimization from 532033: passes AspectJ tests but breaks Spring Framework
//				} else  if (this.getSignature().getDeclaringType() instanceof WildTypePattern) {
//					final WildTypePattern pattern = (WildTypePattern) this.getSignature().getDeclaringType();
//					final ResolvedType type = info.getType();
//					return pattern.matches(type, TypePattern.STATIC);
				}				
			}
		}

		// end ...
		return FuzzyBoolean.MAYBE;
	}

3.2 匹配方法

	// org.springframework.aop.aspectj.AspectJExpressionPointcut#matches(java.lang.reflect.Method, java.lang.Class<?>, boolean)
	@Override
	public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
		obtainPointcutExpression();
		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.
		if (shadowMatch.alwaysMatches()) {
			return 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));
		}
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肯尼思布赖恩埃德蒙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值