在这里插入图片描述

博主 默语带您 Go to New World.
个人主页—— 默语 的博客👦🏻 优秀内容
《java 面试题大全》
《java 专栏》
《idea技术专区》
《spring boot 技术专区》
《MyBatis从入门到精通》
《23种设计模式》
《经典算法学习》
《spring 学习》
《MYSQL从入门到精通》数据库是开发者必会基础之一~
🍩惟余辈才疏学浅,临摹之作或有不妥之处,还请读者海涵指正。☕🍭
🪁 吾期望此文有资助于尔,即使粗浅难及深广,亦备添少许微薄之助。苟未尽善尽美,敬请批评指正,以资改进。!💻⌨


默语是谁?

大家好,我是 默语,别名默语博主,擅长的技术领域包括Java、运维和人工智能。我的技术背景扎实,涵盖了从后端开发到前端框架的各个方面,特别是在Java 性能优化、多线程编程、算法优化等领域有深厚造诣。

目前,我活跃在CSDN、掘金、阿里云和 51CTO等平台,全网拥有超过10万的粉丝,总阅读量超过1400 万。统一 IP 名称为 默语 或者 默语博主。我是 CSDN 博客专家、阿里云专家博主和掘金博客专家,曾获博客专家、优秀社区主理人等多项荣誉,并在 2023 年度博客之星评选中名列前 50。我还是 Java 高级工程师、自媒体博主,北京城市开发者社区的主理人,拥有丰富的项目开发经验和产品设计能力。希望通过我的分享,帮助大家更好地了解和使用各类技术产品,在不断的学习过程中,可以帮助到更多的人,结交更多的朋友.


我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。


AOP:面向切面编程原理简述

在面向切面编程(AOP)中,Spring 通过动态代理机制为目标对象提供增强功能。本文以 AbstractAutoProxyCreator 为核心,简要分析 AOP 的原理和关键实现步骤。


AOP 的入口

AbstractAutoProxyCreator 包含两个关键方法:

  1. 提前暴露 Bean 的引用地址(用于解决循环依赖):getEarlyBeanReference
  2. Bean 初始化后的后置处理postProcessAfterInitialization

两者都会调用 AOP 的核心方法 wrapIfNecessary,这是 AOP 代理逻辑的入口。

// 提前暴露 Bean 的引用
public Object getEarlyBeanReference(Object bean, String beanName) {
    Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
    this.earlyProxyReferences.put(cacheKey, bean); // 缓存
    return this.wrapIfNecessary(bean, beanName, cacheKey); // 包装
}

// 初始化后的后置处理
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) { 
            return this.wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

wrapIfNecessary 方法的作用是为需要增强的 Bean 创建代理对象:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 跳过无需代理的 Bean
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey)) || 
        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;
}

如何识别需要增强的 Bean

wrapIfNecessary 方法调用 getAdvicesAndAdvisorsForBean 确定 Bean 是否需要增强:

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
}

// 筛选合适的增强器
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 获取所有增强器
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // 筛选匹配的增强器
    extendAdvisors(eligibleAdvisors); // 扩展点,允许开发者自定义
    return eligibleAdvisors.isEmpty() ? eligibleAdvisors : sortAdvisors(eligibleAdvisors); // 排序
}

Spring 通过以下两步完成增强器的匹配:

  1. 获取增强器候选列表:从 IOC 容器中查找所有 Advisor 的实现类。

    advisors.add(this.beanFactory.getBean(name, Advisor.class));
    
  2. 筛选匹配的增强器:根据目标类和方法进行匹配。

    public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
        List<Advisor> eligibleAdvisors = new ArrayList<>();
        for (Advisor candidate : candidateAdvisors) {
            if (canApply(candidate, clazz)) { 
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }
    

匹配逻辑中涉及两种增强器:

  • IntroductionAdvisor:类级别增强(如为类添加新功能)。
  • PointcutAdvisor:方法级别增强(如方法执行前后插入逻辑)。

代理对象的创建

一旦识别到需要增强的 Bean,Spring 开始创建代理对象。

protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    if (!proxyFactory.isProxyTargetClass() && shouldProxyTargetClass(beanClass, beanName)) {
        proxyFactory.setProxyTargetClass(true); // 使用 CGLIB
    } else {
        evaluateProxyInterfaces(beanClass, proxyFactory); // 使用 JDK 动态代理
    }

    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    return proxyFactory.getProxy(getProxyClassLoader());
}

代理方式的选择

  1. JDK 动态代理:针对接口生成代理类。
  2. CGLIB 动态代理:针对类生成子类代理。

拦截器链的执行

代理对象拦截方法调用后,执行增强器链(Interceptor Chain):

  • JDK 代理:通过 invoke 方法实现。
  • CGLIB 代理:通过 intercept 方法实现。

以 JDK 动态代理为例:

@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

    if (chain.isEmpty()) {
        return method.invoke(target, args); // 无增强器,直接调用
    } else {
        MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
        return invocation.proceed(); // 调用增强器链
    }
}

总结

Spring 的 AOP 实现通过以下步骤完成:

  1. 识别需要增强的 Bean。
  2. 查找匹配的增强器。
  3. 创建代理对象(JDK 或 CGLIB)。
  4. 执行增强器链。

这一机制使得 Spring 能够灵活地为 Bean 提供切面功能,而开发者无需关注底层的代理实现细节。

在这里插入图片描述


🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批评指正!🍁🐥

如对本文内容有任何疑问、建议或意见,请联系作者,作者将尽力回复并改进📓;(联系微信:Solitudemind )

点击下方名片,加入IT技术核心学习团队。一起探索科技的未来,共同成长。

在这里插入图片描述

更多推荐