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