引
在前面的两节,通过分析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 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 findEligibleAdvisors(Class> beanClass, String beanName) {
// 1、查找所有候选增强
List candidateAdvisors = findCandidateAdvisors();
// 2、从所有增强集合中查找适合当前bean的增强
List 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 findAdvisorsThatCanApply(List candidateAdvisors, Class> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
该工作委托给了AopUtils类的findAdvisorsThatCanApply方法。
public static List findAdvisorsThatCanApply(List candidateAdvisors, Class> clazz) {
// 1、候选增强为空,直接放回
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
// 2、处理引介增强
List 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> 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> 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的所有增强,接下来就是创建代理了。