org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor占内存,
<aop:config> <aop:advisor pointcut="within(cn.com.tcsl.aaa..*.service..*)" advice-ref="transactionAdviceAAA" /> <aop:advisor pointcut="within(cn.com.tcsl.bbb..*.service..*)" advice-ref="transactionAdviceAAA" /> </aop:config> 由于工程类较多,每个DefaultBeanFactoryPointcutAdvisor对象大概占用20MB,6个120MB。
每个DefaultBeanFactoryPointcutAdvisor里面有一个org.springframework.aop.aspectj.AspectJExpressionPointcut对象, 里面有个map,保存着所有匹配的method。
发现每个Map里大概2.5万个method对象, 6个Advisor就是6*2.5万。
挨个看,发现不符合表达式的method也在里面,怀疑aop的匹配有bug,所以看代码。
从DefaultBeanFactoryPointcutAdvisor类下断点,找到了 org.springframework.aop.support.AopUtils类
/** * Determine the sublist of the {@code candidateAdvisors} list * that is applicable to the given class. * @param candidateAdvisors the Advisors to evaluate * @param clazz the target class * @return sublist of Advisors that can apply to an object of the given class * (may be the incoming List as-is) */ public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new LinkedList<Advisor>(); for (Advisor candidate : candidateAdvisors) { 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; }
就是遍历class,看它是否符合某个Advisor的要求。
/** * Can the given pointcut apply at all on the given class? * <p>This is an important test as it can be used to optimize * out a pointcut for a class. * @param pc the static or dynamic pointcut to check * @param targetClass the class to test * @param hasIntroductions whether or not the advisor chain * for this bean includes any introductions * @return whether the pointcut can apply on any method */ public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); if (!pc.getClassFilter().matches(targetClass)) { return false; }
MethodMatcher methodMatcher = pc.getMethodMatcher(); IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; }
Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass); for (Class<?> clazz : classes) { Method[] methods = clazz.getMethods(); for (Method method : methods) { if ((introductionAwareMethodMatcher != null && introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) || methodMatcher.matches(method, targetClass)) { return true; } } }
return false; }
if (!pc.getClassFilter().matches(targetClass)) { return false; } 这个先过滤了一下类,看是否符合表达式。 调到了org.aspectj.weaver.internal.tools.PointcutExpressionImpl
public boolean couldMatchJoinPointsInType(Class aClass) { ResolvedType matchType = world.resolve(aClass.getName()); ReflectionFastMatchInfo info = new ReflectionFastMatchInfo(matchType, null, this.matchContext, world); 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(info),后面带了一个maybeTrue(), fastMatch里只检查了精确匹配和注解那种的,其余都返回MAYBE了,然后返回true了。 就是搞不清的,都算匹配了。 @Pointcut("execution(* com.aaaa.service.*(..))") 实际class是com.bbbb.service.XX,也算成功了。 真是莫名其妙,起码检查一下包路径吧。 匹配之后,后面走method匹配,没看明白。 ------------------- 包括子包 @Pointcut("within(com.aaa..*)")
改成within后走WithinPointcut类,
public FuzzyBoolean fastMatch(FastMatchInfo info) { if (typePattern.annotationPattern instanceof AnyAnnotationTypePattern) { return isWithinType(info.getType()); } return FuzzyBoolean.MAYBE; }
比较了类名,所以最终map里method是对的,只有100多个。
很美好,是吧,换成within后启动慢了10多秒,见鬼了。 折腾好久,发现升级aspectjweaver版本就好了。
|