likes
comments
collection
share

spring aop(三):AnnotationAwareAspectJAutoProxyCreator 分析(下)

作者站长头像
站长
· 阅读数 21

注:本系列源码分析基于spring 5.2.2.RELEASE,本文的分析基于 annotation 注解方式,gitee仓库链接:gitee.com/funcy/sprin….

上一篇文章主要分析了AbstractAutoProxyCreator#postProcessAfterInitialization方法,本文我们来分析AbstractAutoProxyCreator#postProcessAfterInitialization方法。

我们先来看看这个方法的调用链:

|-AnnotationConfigApplicationContext
 |-AbstractApplicationContext#refresh
  |-AbstractApplicationContext#finishBeanFactoryInitialization
   |-ConfigurableListableBeanFactory#preInstantiateSingletons
    |-AbstractBeanFactory#getBean(String)
     |-AbstractBeanFactory#doGetBean
      |-DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory<?>)
       |-ObjectFactory#getObject
        |-AbstractBeanFactory#createBean
         |-AbstractAutowireCapableBeanFactory#doCreateBean
          |-AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)
           |-AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
            |-AbstractAutoProxyCreator#postProcessAfterInitialization

实际上这个方法的调用链就是spring bean的创建过程,我们进入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) {
           // 深入wrapIfNecessary()方法
           return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

继续进入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;
    }

    // 重要代码二:校验此类是否应该被代理,获取这个类的增强
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    //如果获取到了增强则需要针对增强创建代理
    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;
}

这个方法 看着有点长,但大多代码都是在做判断,与aop功能关系不大。真正有关系的代码只有三行:

// 重要代码一:
// 1. isInfrastructureClass:判断当前是否为aop相关类,
//    如Advice/Pointcut/Advisor等的子类,是否包含 @AspectJ的注解
// 2. shouldSkip:查找所有切面类,判断是否被排除
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    ...
}

// 重要代码二:校验此类是否应该被代理,获取这个类的增强
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

// 重要代码三:创建代理
Object proxy = createProxy(
    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

对于重要代码一,上一篇文章已经分析过,本文我们主要分析重要代码二重要代码三

1. 获取类的增强

AbstractAdvisorAutoProxyCreator

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
        Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    // 查找符合条件的增强,继续往下看
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}

/**
 * 查找符合条件的增强
 */
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    //获取容器中的所有增强,在上一篇文章中已经分析过了
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    //验证beanClass是否该被代理,如果应该,则返回适用于这个bean的增强
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

/**
 * 验证beanClass是否该被代理
 */
protected List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
        // 验证beanClass是否该被代理
        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    }
    finally {
        ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
}

spring的方法调用比较深,一路追踪,最终到了AopUtils.findAdvisorsThatCanApply方法,继续往下看:

AopUtils

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    }
    List<Advisor> eligibleAdvisors = new ArrayList<>();
    // 遍历 candidateAdvisors,判断是否满足代理条件
    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;
        }
        //对普通bean的处理
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }
    return eligibleAdvisors;
}

/**
 * 判断是否需要增强
 */
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
    // 调用下一个方法
    return canApply(advisor, targetClass, false);
}

/**
 * 判断是否需要增强
 */
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;
        //进入该方法继续
        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) {
    Assert.notNull(pc, "Pointcut must not be null");
    //切点上是否存在排除类的配置
    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;
    }

    // classes包含targetClass、除Object的所有父类、所有接口
    Set<Class<?>> classes = new LinkedHashSet<>();
    if (!Proxy.isProxyClass(targetClass)) {
        classes.add(ClassUtils.getUserClass(targetClass));
    }
    classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

    // 循环判断方法是否需要代理,
    // 这里可以看出,
    // 1. 只要一个方法满足代理要求,那么整个类就会被代理
    // 2. 如果父类有方法需要被代理,那么子类也会被代理
    for (Class<?> clazz : classes) {
         // 获取 clazz 定义的方法
         // 包括当前类的方法、除Object外的所有父类方法、接口的默认方法
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        for (Method method : methods) {
            //获取类所实现的所有接口和所有类层级的方法,循环验证
            if (introductionAwareMethodMatcher != null ?
                introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }

    return false;
}

看到这里,基本上就了解了spring是如何来判断一个对象是否需要被代理的,这里总结流程如下:

  1. 获取到项目中所有的切面对象,将其中的切面方法封装为一个List<Advisor>,具体操作在上一篇文章中有详细分析;
  2. 遍历Advisor,对每一个Advisor,利用反射获取当前类的除Object外的所有父类及接口,结果为Set<Class>
  3. 遍历Set<Class>,对其中每一个Class,利用反射获取该Class方法、除Object外的所有父类的方法、接口的默认方法,结果为Method[];
  4. 遍历Method[],如果有一个method满足Advisor的切面条件,则表示当前Advisor可以应用到当前bean,该bean就需要被代理,这一步最终得到的结果也是一个List<Advisor>,表示该有多个Advisor 需要应用到该对象。

伪代码类似于:

// 1. 获取所有的Advisor
List<Advisor> advisorList = getAdvisorList();
// 2. 遍历Advisor
for(Advisor advisor : advisorList) {
    // 获取当前类的除`Object`外的所有父类及接口,classSet也包含targetClass
    Set<Class> classSet = getSuperClassAndInterfaces(targetClass);
    for(Class cls : classSet) {
        // 遍历cls中定义的方法,包括当前类的方法、除Object外的所有父类方法、接口的默认方法
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        //  遍历这些方法
        for (Method method : methods) {
             // 判断method是否满足切面条件
        }
    }
}

得到List<Advisor>后,接下来就是根据List<Advisor>来创建代理对象了。

2. 创建代理对象

我们来看看spring创建代理对象的流程。

AbstractAutoProxyCreator#wrapIfNecessary

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    ...
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 代理对象就是在这里创建的
        // - specificInterceptors:可以应用到该对象的  Advisor,
        //    specificInterceptors的获取过程,上一部分已经详细分析过了,不再赘述了
        // - SingletonTargetSource:对原始对象的一个包装
        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;
}

我们先来看看SingletonTargetSource

public class SingletonTargetSource implements TargetSource, Serializable {

    private static final long serialVersionUID = 9031246629662423738L;

    private final Object target;

    public SingletonTargetSource(Object target) {
        Assert.notNull(target, "Target object must not be null");
        this.target = target;
    }

    @Override
    public Class<?> getTargetClass() {
        return this.target.getClass();
    }

    @Override
    public Object getTarget() {
        return this.target;
    }

    ...
}

这个类代码很简单,就是对原始对象做了一层包装。继续往下看:

AbstractAutoProxyCreator#createProxy

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) 
            this.beanFactory, beanName, beanClass);
    }

    ProxyFactory proxyFactory = new ProxyFactory();
    //使用proxyFactory对象copy当前类中的相关属性
    proxyFactory.copyFrom(this);

    // 判断是否使用Cglib动态代理,可以在注解中指定:
    // @EnableAspectJAutoProxy(proxyTargetClass = true)
    if (!proxyFactory.isProxyTargetClass()) {
        // 如果 beanFactory 是 ConfigurableListableBeanFactory,
        // 则可在 BeanDefinition 设置属性,单独控制某一个类使用 cglib 代理
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            // 如果没有配置开启, 则判断bean是否有合适的接口使用JDK的动态代理
            // 注意:JDK动态代理必须是带有接口的类
            // 如果类没有实现任何接口则只能使用Cglib动态代理)
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    // 构建Advisor,这里包含两个操作:
    // 1. 添加公共的 Interceptor
    // 2. 对于给定的advisor,判断其类型,然后转换为其具体类型
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    //添加所有增强
    proxyFactory.addAdvisors(advisors);
    //设置要代理的类
    proxyFactory.setTargetSource(targetSource);
    //Spring的一个扩展点,默认实现为空。留给我们在需要对代理进行特殊操作的时候实现
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
    //使用代理工厂获取代理对象
    return proxyFactory.getProxy(getProxyClassLoader());
}

@EnableAspectJAutoProxy注解中,可以使用proxyTargetClass = true来设置项目使用cglib代理,这在代码中也有体现:

// 只有在proxyFactory.isProxyTargetClass()为false时,才会进行下面的判断
// 换言之,当 @EnableAspectJAutoProxy(proxyTargetClass = true) 时
// 下面的代码是不会运行的,默认使用就是cglib代理
if (!proxyFactory.isProxyTargetClass()) {
    // 判断有没在 BeanDefinition 中设置使用 cglib代理
    if (shouldProxyTargetClass(beanClass, beanName)) {
        proxyFactory.setProxyTargetClass(true);
    }
    else {
        // 是否满足代理接口的条件,即是否满足jdk动态代理的条件
        evaluateProxyInterfaces(beanClass, proxyFactory);
    }
}

spring是如何判断一个类是否满足jdk动态代理的条件的呢?从我们来认知上来说,实现了接口,就可以使用动态代理,否则就只能使用cglib代理,我们来看看spring是如何判断的:

ProxyProcessorSupport#evaluateProxyInterfaces

/**
 * 判断是否能使用jdk动态代理
 */
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
    // 获取类的所有接口
    Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
    boolean hasReasonableProxyInterface = false;
    for (Class<?> ifc : targetInterfaces) {
        // 1.isConfigurationCallbackInterface: 判断ifc是否为InitializingBean,DisposableBean,
        //   Closeable,AutoCloseable,以及包含 Aware
        // 2.isInternalLanguageInterface: 是否为内部语言接口,如groovy,mock等
        // 3.ifc.getMethods().length > 0:接口的方法数必须大于1
        if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
                ifc.getMethods().length > 0) {
            hasReasonableProxyInterface = true;
            break;
        }
    }
    if (hasReasonableProxyInterface) {
         // 需要将所有的接口都设置到proxyFactory
         // 试想一下,如果一个类A 实现了接口 I1 与 I2,
         // 如果类A的对象a  托管到了spring容器,那么无论是使用 beanFactory.get(I1.class),
         // 还是 beanFactory.get(I1.class),都应该能获取到a.
         for (Class<?> ifc : targetInterfaces) {
             proxyFactory.addInterface(ifc);
         }
    }
    else {
        proxyFactory.setProxyTargetClass(true);
    }
}

从源码上来看,spring判断是否能使用jdk动态代理的过程与我们认知上的差不多,不过并不是实现了任意接口就能使用jdk动态代理,spring会排除InitializingBeanDisposableBeanCloseableAutoCloseable等接口,同时也会排除无任何方法的接口。

分析完spring如何判断是否使用jdk动态代理后,接口我们来看看spring是如何创建代理对象的。为了说明问题,首先简化下AbstractAutoProxyCreator#createProxy

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    // 省略一些代码
    ...
    ProxyFactory proxyFactory = new ProxyFactory();
    //使用proxyFactory对象copy当前类中的相关属性
    proxyFactory.copyFrom(this);
    // 这里省略了好多的判断
    proxyFactory.setProxyTargetClass(true);
    //添加所有增强
    proxyFactory.addAdvisors(advisors);
    //设置要代理的类
    proxyFactory.setTargetSource(targetSource);
    ...
    //使用代理工厂获取代理对象
    return proxyFactory.getProxy(getProxyClassLoader());
}

从这里可以看出,这个方法创建了一个ProxyFactory对象,然后往该对象的属性里设置了一些值。继续往下看:

ProxyFactory#getProxy(java.lang.ClassLoader)

public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}

这里有两个方法:createAopProxy()getProxy(classLoader),我们先来看createAopProxy()

ProxyCreatorSupport#createAopProxy

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
         activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}

继续,

DefaultAopProxyFactory#createAopProxy

/**
 * 判断代理类型
 * 如果能使用jdk动态代理,就返回 JdkDynamicAopProxy
 * 否则就返回 ObjenesisCglibAopProxy
 */
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException(...);
        }
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

到这里,我们就能明白,JdkDynamicAopProxy是用来处理jdk动态代理的,ObjenesisCglibAopProxy是用来处理cglib代理的。接下来,我们来看看getProxy(classLoader) 方法。

JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    Class<?>[] proxiedInterfaces = AopProxyUtils
            .completeProxiedInterfaces(this.advised, true);
    // 是否有equals()与hashCode()方法
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // 调用 jdk 方法 创建对象
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

最后我们来看看得到的代理对象是什么样的:

spring aop(三):AnnotationAwareAspectJAutoProxyCreator 分析(下)

可以看到,代理对象的h属性保存的就是JdkDynamicAopProxy对象,JdkDynamicAopProxy对象的advised属性保存了代理的代理的相关信息。

CglibAopProxy#getProxy(java.lang.ClassLoader)

public Object getProxy(@Nullable ClassLoader classLoader) {
    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, "xxx");

        Class<?> proxySuperClass = rootClass;
        if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
            proxySuperClass = rootClass.getSuperclass();
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        validateClassIfNecessary(proxySuperClass, classLoader);

        // 创建 Enhancer 对象,并set一些属性
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                    ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        // Superclass就是要代理的类
        enhancer.setSuperclass(proxySuperClass);
        // 设置接口,如 SpringProxy,Advised
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), 
                this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        return createProxyClassAndInstance(enhancer, callbacks);
    }
    catch (CodeGenerationException | IllegalArgumentException ex) {
        throw new AopConfigException(...);
    }
    catch (Throwable ex) {
        throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

spring使用cglib创建对象,主要用到了Enhancer类,关于这一块后面会再分析。

最后我们也来看看创建后得到的对象:

spring aop(三):AnnotationAwareAspectJAutoProxyCreator 分析(下)

3. 总结

本文主要分析了AbstractAutoProxyCreator#postProcessAfterInitialization,该方法主要做了三件事:

  1. 获取项目中所有切面类,将切点方法包装为List<advisor>:实际上,这一步的操作也会在 AbstractAutoProxyCreator#postProcessBeforeInitialization 中执行,然后将结果缓存了起来,这一步其实是直接在缓存中拿结果;
  2. 获取当前对象的所有增强:这一步就是判断哪些增强可以用于当前对象,判断时先获取当前类的所有接口与不包括Object的父类,然后逐一判断这些接口与类中的方法是否满足增强条件,只要有一个方法满足,就表示当前对象需要被代理;
  3. 创建代理对象:创建代理对象时,默认情况下,会根据是否实现了接口来选择使用jdk动态代理还是cglib,可应用于当前bean的List<advisor>也会封装进代理对象中。

本文原文链接:my.oschina.net/funcy/blog/… ,限于作者个人水平,文中难免有错误之处,欢迎指正!原创不易,商业转载请联系作者获得授权,非商业转载请注明出处。

本系列的其他文章

【spring源码分析】spring源码分析系列目录