SpringBoot源码解读与原理分析(二十九)AOP模块的生命周期(二)代理对象的生成

前言

在AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator的postProcessBeforeInstantiation方法中,有一个TargetSource的设计:

代码清单1AbstractAutoProxyCreator.java

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    // ......

    // 源码注释:如果我们有一个自定义的TargetSource,在这里创建代理;TargetSource将以自定义方式处理目标实例。
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

由 代码清单1 可知,TargetSource的设计与AOP代理有关。

9.4 TargetSource的设计

实际上,AOP的代理并不是代理目标对象本身,而是目标对象经过包装后的TargetSource对象。

9.4.1 与Java原生动态代理的区别

在Java原生动态代理中,代理对象中直接组合了原始对象:

Java原生动态代理

而在AOP中,代理对象并没有直接代理target,而是给target加了一个“壳”,即TargetSource:

AOP代理

TargetSource对象可以看作目标对象的一个包装、容器,Java原生动态代理在执行method.invoke(target, args)时,获取的是目标对象;但被TargetSource包装后,就只能改用method.invoke(targetSource.getTarget(), args)进行。

9.4.2 TargetSource的好处

上述两种方式,最终结果都会拿到目标对象target,但getTarget方法可以提供一个可扩展的切入点,决定如何返回目标对象。

例如,每次getTarget方法返回的target对象可以不一致,或者从一个对象池中获取。

总的来说,让AOP代理TargetSource的好处是可以控制每次方法调用的作用的具体对象实例,从而让方法的调用更灵活。

9.4.3 TargetSource的结构

代码清单2TargetSource.java

public interface TargetSource extends TargetClassAware {
    Class<?> getTargetClass();
    boolean isStatic();
    Object getTarget() throws Exception;
    void releaseTarget(Object target) throws Exception;
}

由 代码清单2 可知,TargetSource是一个接口,定义了几个方法:

  • getTarget:获取target对象。
  • releaseTarget:释放target对象。
  • isStatic:是否静态bean对象。单实例bean对象就为“静态bean对象”,原型bean对象就为“非静态bean对象”。

9.4.4 SpringFramework中提供的TargetSource

SpringFramework针对不同场景和不同需求,预设了几个TargetSource的实现:

  • SingletonTargetSource:单实例TargetSource,每次调用getTarget方法都会返回同一个目标对象(与Java原生动态代理无任何区别);
  • PrototypeTargetSource:原型TargetSource,每次调用getTarget方法都会从BeanFactory中创建一个全新的目标对象(被它包装的目标对象必须为原型bean对象);
  • CommonsPool2TargetSource:内部维护了一个对象池,每次调用getTarget方法都会从对象池中提取出对象(底层使用Apache的ObjectPool);
  • ThreadLocalTargetSource:本地线程TargetSource,每次调用getTarget方法都会从它所处的线程中提取目标对象(由于每个线程都有一个TargetSource,因此被它包装的目标对象也必须为原型bean对象);
  • HotSwappableTargetSource:支持热替换的TargetSource,内部维护一个可以热替换的目标对象引用,每次调用getTarget方法都会返回它。

9.5 代理对象生成的核心:wrapIfNecessary

SpringBoot源码解读与原理分析(二十八)AOP模块的生命周期(一) 9.2.3.2 postProcessAfterInitialization 中提到,bean对象的初始化会被BeanPostProcessor的postProcessAfterInitialization方法处理,进入AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization方法中,该方法又要调用wrapIfNecessary方法尝试创建代理对象。

代码清单3AbstractAutoProxyCreator.java

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

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);
        // 创建代理对象的动作
        // 创建SingletonTargetSource,将bean对象包装起来
        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;
}

由 代码清单3 可知,wrapIfNecessary方法的逻辑很清晰,先判断是否是不会被增强的对象,如果不是则会获取增强器集合,并创建由SingletonTargetSource包装的代理对象。

9.5.1 getAdvicesAndAdvisorsForBean

从方法名就能知道,getAdvicesAndAdvisorsForBean方法会根据当前正在初始化的bean对象,匹配可织入通知的增强器。

代码清单4AbstractAdvisorAutoProxyCreator.java

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();
    // 筛选出可以切入当前bean对象的增强器
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    // 添加额外的增强器
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        // 增强器排序
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

由 代码清单4 可知,getAdvicesAndAdvisorsForBean方法又会调用findEligibleAdvisors方法,后者的逻辑也很清晰:获取所有增强器;筛选出可以切入当前bean对象的增强器;添加额外的增强器;增强器排序。

9.5.1.1 findCandidateAdvisors

这个方法已经梳理过,详见 SpringBoot源码解读与原理分析(二十八)AOP模块的生命周期(一) 9.3 Advisor与切面类的收集 ,是同一个方法。

9.5.1.2 findAdvisorsThatCanApply

获取到所有候选增强器之后,接着匹配可以切入当前正在初始化的bean对象的增强器。

代码清单5AbstractAdvisorAutoProxyCreator.java

protected List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    } finally {
        ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
}
代码清单6AopUtils.java

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    }
    List<Advisor> eligibleAdvisors = new ArrayList<>();
    // 匹配引介增强器
    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;
}

由 代码清单5、6 可知,匹配动作最终由AopUtils的findAdvisorsThatCanApply实现,主体逻辑分为匹配引介增强器、匹配普通方法增强器。在实际项目开发中,几乎不会用到引介通知,因此重点放在普通方法通知封装的增强器。

代码清单7AopUtils.java

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 {
        // 位置类型,默认可以匹配
        return true;
    }
}

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    Assert.notNull(pc, "Pointcut must not be null");
    // 如果切入点无法应用于当前bean对象,则直接返回false
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    }

    // ......

    // 收集当前bean对象继承的父类和实现的接口
    // 因为切入点表达式可能切的是父类或接口
    Set<Class<?>> classes = new LinkedHashSet<>();
    if (!Proxy.isProxyClass(targetClass)) {
        classes.add(ClassUtils.getUserClass(targetClass));
    }
    classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

    for (Class<?> clazz : classes) {
        // 逐个判断每个方法能否被当前切入点表达式切入,能则立即返回true
        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;
}

由 代码清单7 可知,canApply方法会针对不同类型的增强器分别采用不同的判断逻辑。对于普通方法通知封装的增强器,会转调重载的canApply方法。在该重载方法中,利用MethodMatcher逐个判断每个方法能否被当前切入点表达式切入。

9.5.1.3 extendAdvisors

由 代码清单4 可知,getAdvicesAndAdvisorsForBean方法的第三步是添加额外的增强器extendAdvisors方法。

代码清单8AspectJAwareAdvisorAutoProxyCreator.java

protected void extendAdvisors(List<Advisor> candidateAdvisors) {
    AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
代码清单9AspectJProxyUtils.java

public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
    // Don't add advisors to an empty list; may indicate that proxying is just not required
    if (!advisors.isEmpty()) {
        // 判断是否有AspectJ封装的增强器
        boolean foundAspectJAdvice = false;
        for (Advisor advisor : advisors) {
            if (isAspectJAdvice(advisor)) {
                foundAspectJAdvice = true;
                break;
            }
        }
        // 如果发现有AspectJ封装的增强器,则添加一个ExposeInvocationInterceptor.ADVISOR
        if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
            advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
            return true;
        }
    }
    return false;
}

由 代码清单8、9 可知,extendAdvisors会判断当前可用的增强器中是否有AspectJ封装的增强器,如果有则在整个增强器列表的最前端添加一个ExposeInvocationInterceptor.ADVISOR。

代码清单10ExposeInvocationInterceptor.java

public static final ExposeInvocationInterceptor INSTANCE = new ExposeInvocationInterceptor();
public static final Advisor ADVISOR = new DefaultPointcutAdvisor(INSTANCE) {
    @Override
    public String toString() {
        return ExposeInvocationInterceptor.class.getName() +".ADVISOR";
    }
};

private static final ThreadLocal<MethodInvocation> invocation =
			new NamedThreadLocal<>("Current AOP method invocation");
public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    } finally {
        invocation.set(oldInvocation);
    }
}

由 代码清单10 可知,ExposeInvocationInterceptor.ADVISOR是一个DefaultPointcutAdvisor,是一个对所有bean对象都生效的增强器。其invoke方法会向当前线程的ThreadLocal中放入当前正在执行的代理对象的方法执行包装(MethodInvocation)

并且,把该增强器放在增强器列表的最前端,那后面的增强器都可以获取到当前正在执行的MethodInvocation对象。

9.5.2 createProxy

回到wrapIfNecessary方法,getAdvicesAndAdvisorsForBean方法执行完毕后,下一步就是创建代理对象createProxy方法。

代码清单11AbstractAutoProxyCreator.java

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
                             @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    // ......
    
    // 代理工厂的初始化
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);
    // 根据AOP的设计,决定是否强制使用Cglib
    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            // Cglib动态代理直接记录被代理bean对象的所属类即可
            proxyFactory.setProxyTargetClass(true);
        } else {
            // 解析被代理bean对象所属类的所有实现的接口
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    // 收集整理要织入目标对象的通知增强器
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
    // 创建代理对象
    return proxyFactory.getProxy(getProxyClassLoader());
}

由 代码清单11 可知,createProxy方法的核心步骤是:收集整理要织入目标对象的通知增强器;创建代理对象。

9.5.2.1 buildAdvisors
代码清单12AbstractAutoProxyCreator.java

protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
    // 适配SpringFramework原生AOP的MethodInterceptor
    Advisor[] commonInterceptors = resolveInterceptorNames();
    List<Object> allInterceptors = new ArrayList<>();
    if (specificInterceptors != null) {
        if (specificInterceptors.length > 0) {
            allInterceptors.addAll(Arrays.asList(specificInterceptors));
        }
        if (commonInterceptors.length > 0) {
            if (this.applyCommonInterceptorsFirst) {
                allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
            } else {
                allInterceptors.addAll(Arrays.asList(commonInterceptors));
            }
        }
    }
    // logger ...
    // 将 支持转换/包装为Advisor类型的对象 适配成Advisor
    Advisor[] advisors = new Advisor[allInterceptors.size()];
    for (int i = 0; i < allInterceptors.size(); i++) {
        advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
    }
    return advisors;
}

由 代码清单12 可知,buildAdvisors方法将收集好的增强器specificInterceptors放入了allInterceptors,并将其中的支持转换/包装为Advisor类型的对象(即MethodInterceptor和AdvisorAdapter)适配成Advisor。

9.5.2.2 proxyFactory.getProxy
代码清单13ProxyFactory.java

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

由 代码清单13 可知,getProxy方法又分为两步:

(1)createAopProxy
代码清单14ProxyCreatorSupport.java

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

public AopProxyFactory getAopProxyFactory() {
    return this.aopProxyFactory;
}

由 代码清单14 可知,createAopProxy方法会先获取一个AopProxyFactory,在调用其createAopProxy方法得到一个AopProxy。

默认的AopProxyFactory类型是DefaultAopProxyFactory类。

代码清单15DefaultAopProxyFactory.java

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        // 如果要代理的本身是接口,或者已经被JDK动态代理的代理对象,则使用JDK动态代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // 否则使用Cglib动态代理
        return new ObjenesisCglibAopProxy(config);
    } else {
        return new JdkDynamicAopProxy(config);
    }
}
(2)getProxy

创建完AopProxy,接下来开始创建代理对象。

  • JDK动态代理JdkDynamicAopProxy
代码清单16JdkDynamicAopProxy.java

public Object getProxy(@Nullable ClassLoader classLoader) {
    // logger ...
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

由 代码清单16 可知,底层创建代理对象使用的是Proxy.newProxyInstance

  • Cglib动态代理ObjenesisCglibAopProxy
代码清单17ObjenesisCglibAopProxy.java

public Object getProxy(@Nullable ClassLoader classLoader) {
    // ......

    // Configure CGLIB Enhancer...
    Enhancer enhancer = createEnhancer();
    // 设置类加载器、父类、接口等信息
    
    // ......

    // 创建代理对象
    return createProxyClassAndInstance(enhancer, callbacks);
}

由 代码清单17 可知,Cglib动态代理的创建逻辑,核心动作还是对Enhancer进行操作。

至此,代理对象被成功创建,整个AOP通知织入的流程结束。随着IOC容器刷新完成,所有代理对象也都全部创建完毕。

······

本节完,更多内容请查阅分类专栏:SpringBoot源码解读与原理分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

维先生d

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

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

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

打赏作者

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

抵扣说明:

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

余额充值