Spring Aop源码解析与细节

Cesium 实战 19 - 使用 gltf-vscode 查看、预览以及编辑 glTF 和 GLB 模型 Cesium 实战 - 使用 gltf-vscode 查看、预览以及编辑 glTF 和 GLB 模型。 阅读详情

终于看完了庞大的Spring core(spring ioc / spring aop),鉴于ioc更为庞大,先整理下aop的源码流程,也能简单回顾下springioc的流程

首先要理解spring bean的启动大致的流程与生命周期,建议看另一篇已经简要解释 spring生命周期

基础概念
AOP 与 Spring AOP 与 AspectJ的区别

AOP 是思想,Spring AOP 与 AspectJ是AOP的实现,Spring AOP实现的时候用了AspectJ的规范

基本使用与AOP概念

//TODO

源码解析
入口

1、AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Application.class);
refresh()初始化bean和执行后置处理器
2、@EnableAspectJAutoProxy
添加AOP的后置处理器,等同于xml中的 aop:aspectj-autoproxy/

@EnableAspectJAutoProxy解析

1、@EnableAspectJAutoProxy注解中@Import了类AspectJAutoProxyRegistrar,AspectJAutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar,可以拿到BeanDefinitionRegistry(spring bean生命周期相关),可以在类初始化之前加入AOP的后置处理器 ----> AnnotationAwareAspectJAutoProxyCreator
在这里插入图片描述

2、AnnotationAwareAspectJAutoProxyCreator的父类实现了BeanPostProcessor,会在spring对象产生之后进行操作,spring最核心的扩展点
3、父类实现BeanPostProcessor,真正执行后置处理器的类在AbstractAutoProxyCreator#postProcessAfterInitialization

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

其中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;
		}

		// Create proxy if we have advice.
		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;
	}

4、动态代理的选择方式 (jdk、cjlib) DefaultAopProxyFactory#createAopProxy

// 这段代码有前人解释的很好了
public AopProxy DefaultAopProxyFactory#createAopProxy(AdvisedSupport config) throws AopConfigException {
    //这段代码用来判断选择哪种创建代理对象的方式
    //config.isOptimize()   是否对代理类的生成使用策略优化 其作用是和isProxyTargetClass是一样的 默认为false
    //config.isProxyTargetClass() 是否使用Cglib的方式创建代理对象 默认为false
    //hasNoUserSuppliedProxyInterfaces目标类是否有接口存在 且只有一个接口的时候接口类型不是
    //SpringProxy类型 
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        //上面的三个方法有一个为true的话,则进入到这里
        //从AdvisedSupport中获取目标类 类对象
        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的方式生成代理对象
        //如果目标类是Proxy类型 则还是使用JDK的方式生成代理对象
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        //配置了使用Cglib进行动态代理  或者目标类没有接口 那么使用Cglib的方式创建代理对象
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        //上面的三个方法没有一个为true 那使用JDK的提供的代理方式生成代理对象
        return new JdkDynamicAopProxy(config);
    }
}

用户可以自行配置@EnableAspectJAutoProxy注解有一个proxyTargetClass属性表示是否使用CGLIB进行代理,源码中可以看出,即便是自定义了CGLIB代理,如果是个接口口,依旧会选择jdk动态代理

jdk动态代理

public Object JdkDynamicAopProxy#getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

Cglib动态代理

	protected Object ObjenesisCglibAopProxy#createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
		Class<?> proxyClass = enhancer.createClass();
		Object proxyInstance = null;

		if (objenesis.isWorthTrying()) {
			try {
				proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
			}
			catch (Throwable ex) {
				logger.debug("Unable to instantiate proxy using Objenesis, " +
						"falling back to regular proxy construction", ex);
			}
		}

		if (proxyInstance == null) {
			// Regular instantiation via default constructor...
			try {
				Constructor<?> ctor = (this.constructorArgs != null ?
						proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
						proxyClass.getDeclaredConstructor());
				ReflectionUtils.makeAccessible(ctor);
				proxyInstance = (this.constructorArgs != null ?
						ctor.newInstance(this.constructorArgs) : ctor.newInstance());
			}
			catch (Throwable ex) {
				throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
						"and regular proxy instantiation via default constructor fails as well", ex);
			}
		}

		((Factory) proxyInstance).setCallbacks(callbacks);
		return proxyInstance;
	}
后置处理器在哪里执行的呢(spring bean相关,简略说一下) 以注解为例

入口: AnnotationConfigApplicationContext的构造方法中的 refresh()方法

一个问题: 代理类生成的时机是getbean的时候还是getbean之前呢?
答案: 在getbean之前,在AnnotationConfigApplicationContext构造方法中执行了refresh方法,执行了getbean实例化,并生成了代理类(源码解读)

refresh()方法中进行了较多的操作,实例化工厂、配置工厂、生成db、注册beanPostProcessor…,我们的重点在finishBeanFactoryInitialization(beanFactory);方法中

然后进入到默认工厂类DefaultListableBeanFactory#preInstantiateSingletons#getBean()

准备进入核心代码:(后面补上完整调用链)
AbstractAutowireCapableBeanFactory#doCreateBean(去除了干扰代码)

	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
		
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			//设置属性,非常重要
			populateBean(beanName, mbd, instanceWrapper);
			//执行后置处理器,aop就是在这里完成的处理
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {}

}

AbstractAutowireCapableBeanFactory#initializeBean
这里执行了后置处理器的after方法,这里就会执行第一步中注册的后置处理器,这里也能看出BeanPostProcessors执行的时机和spring bean创建的时机

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//执行后置处理的befor
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//执行bean的声明周期回调中的init方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
	
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//执行后置处理器的after方法
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}
开源模型应用落地-qwen模型小试-Qwen3-8B-快速体验(一) 阿里云推出国内首个集成“快思考”与“慢思考”能力的 Qwen3-8B 大语言模型,以80亿参数和 128K 上下文支持,重塑AI应用边界并助力开发者高效部署 阅读详情

相关推荐

Halcon实战:如何快速找到图像中的多个圆并计算圆心距离(附完整代码)

本文详细介绍了Halcon在工业视觉检测中快速定位图像中的多个圆并计算圆心间距离的实战方法。通过两种核心算法(阈值分割和动态阈值)的对比分析,结合完整代码示例和参数调优技巧,帮助开发者高效解决多圆检测问题,提升工业检测精度与效率。

weixin_33701251的博客 316

Spring5 源码阅读笔记(1)refresh() 刷新

入口 private ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); 有了 applicationContet 之后,就可进行 getBean(beanName) 操作。 与 ClassPathXmlApplicationContext 平行的还有: FileSy...

日有寸进 561

WorkBuddy驱动SolidWorks实测:AI建模流程、参数化与许可排查指南

AI辅助三维建模正在改变工程师的重复劳动方式。其核心理念不是替代人的设计决策,而是通过AI智能体接管CAD软件中的草图绘制、特征创建、尺寸修改等高频操作,让工程师从繁琐的GUI交互中解放出来。在SolidWorks这类主流CAD平台上,这类AI助手的落地依赖环境稳定、需求描述清晰和参数化建模规范。通过将外径、孔距等关键尺寸定义为全局变量并用方程式驱动,可实现改一个数、模型自动更新的高效流程;同时,遇到“无法获得许可”等环境故障时,需要按服务状态、安全软件隔离、干净卸载的顺序排查。以WorkBuddy驱动So

weixin_28559803的博客 361

Spring框架核心源码解析:IoC容器与AOP动态代理实现细节

Dubbo的调用链路设计体现了高质量RPC框架的架构思想:通过动态代理实现透明化远程调用,通过集群容错保证系统可靠性,通过负载均衡实现流量优化。深入理解Dubbo调用链路的每个环节,对于构建高可用分布式系统具有重要意义。随着Dubbo 3.x在云原生领域的持续演进,其调用链路将进一步优化,为微服务架构提供更强大的支持。

2501_93831841的博客 886

AD(Altium Designer)器件封装——立创商城导出原理图和PCB完成器件封装操作指南

官网:www.SZLCSC.COM以芯片为例器件类——>芯片类——>对应芯片确定芯片——>数据手册1:原理图2:PCB3:打开操作流程选中原理图——>文件——>导出——>AD1: ✔2:导出AD文件操作流程选中PCB图——>文件——>导出——>AD1: ✔2:导出AD文件1:PCB图2:原理图操作流程文件——>打开操作流程选中文件——>打开操作流程项目文件——>添加新的...到工程——>Schematic Library新原理图库操作流程项目文件——>添加新的...到工程——>PCB Library新的PC

XU157303764的博客 5436

POCV/SOCV 、LVF的差别

1.POCV与OCV、AOCV 为了模拟片上PVT的差异带来的影响,最早提出了OCV(On Chip Variation)给每个cell都设置一个固定的derate值,来覆盖最悲观的情况,但是随着工艺发展,设计规模增大,OCV过度的悲观开始限制性能,于是又有了AOCV(Advanced On Chip Variation),用基于depth和distance的derate来取代单一的全局的derate值,但时序收敛的过程中逻辑级数depth的变化让时序分析的时间变得非常长,由此POCV诞生了。 POCV

m0_61544122的博客 5361

框架源码专题:Spring的Aop实现原理,Spring AOP 与 AspectJ 的关系

文章目录1. Spring AOP 与 AspectJ 的关系2. Spring AOP术语解释3. Spring AOP应用实例4. Spring AOP有几种配置方式?5. Spring AOP源码解析 1. Spring AOP 与 AspectJ 的关系         Spring AOP 要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者增强

qq_1149513559的博客 1333

【局部规划模块轨迹优化算法】Teb_planner规划算法

认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长!本文先对****做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容由于ROS中的局部路径规划器比较老了,所以我推荐大家使用比较新的局部路径规划器teb_local_planner。teb_local_planner是基于弹性时间带碰撞约束的算法,算法将动态障碍物、运行时效、路径平滑性等约束做综合考虑,在复杂环境下有更优秀的表现。

qq_35635374的博客 951

Spring AOP源码解析-核心组件解析及筛选合适的通知器

一.简介 首先,我们先看这篇文章:AOP详解,从这篇文章中回顾了关于AOP的一些专业术语。从这篇文章开始,我将会对Spring AOP部分的源码来进行解析,本文主要分析Spring AOP是如何为目标bean筛选合适的通知器。 二.源码分析 2.1 AOP入口分析 首先,我们要思考一个问题,Spring是如何将AOP和IOC模块整合到一起的? 在之前的文章:Bean的生命周期,我们了解到...

努力找工作呀 499

YOLO26 网络结构逐模块解析:Backbone/Neck/Head

本文解析了YOLO26目标检测网络的架构设计,重点介绍其在Backbone、Neck和Head三个核心组件的创新优化。Backbone采用改进的CSP模块与轻量级注意力机制,提升特征提取效率;Neck使用改进的BiFPN结构实现高效多尺度特征融合;Head采用完全解耦设计简化回归流程。文章详细分析了各模块的技术演进、实现细节和设计思想,通过流程图和代码示例展示了YOLO26的整体架构和关键组件实现。该研究对模型优化、定制开发和硬件部署具有重要指导意义。

一键难忘的博客 1241

8155源码编译DSP(ubuntu环境下)

一.设置环境变量 -users:/$ sudo gedit ~/.bashrc #set adsp cdsp tools path #export ARMLMD_LICENSE_FILE=<LICENSE FILE INFO> #export ARMTOOLS=RVCT221 #export ARMROOT=/pkg/asw/compilers/arm/ADS1.2 #export ARM_COMPILER_PATH=/pkg/qct/software/arm/RVDS/2.2BLD593

Johnny2004的专栏 1676

11_spring事务源码解析

@EnableTransactionManagement注解的具体实现。以及怎么使用aop来实现事务的。其实主要是后置处理器实现事务在什么时候执行。切面类实现事务增强的具体逻辑。

qq_35175478的博客 984

半导体设备系列(2) 半导体设备与工厂控制仿真器Demo编写

基于C/S架构用C++编写半导体设备仿真器与工厂控制仿真器

追赶时代的博客 610

spring.aop 随笔1 主流程

Java 随笔 代理模式 1-spring aop

hyoka的博客 336

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Spring源码分析

文章目录为什么要看Spring源码如何看源码Spring中的IoC容器BeanFactoryBeanDefinitionSpring容器的初始化流程IoC容器的使用容器初始化入口解析&amp;注册BeanDefinitionBeanDefinitionReader继承结构总结一下Bean的实例化&amp;依赖注入bean实力化小结循环依赖问题Spring AOP原理查找BeanDefinition...

不瘦十斤不换名字 1592

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

深入聊一聊 Spring AOP 实现机制

来源:吉姆餐厅ak概述AOP(Aspect-Oriented Programming) 面向切面编程。Spring Aop 在 Spring框架中的地位举足轻重,主要用于...

程序猿DD 1238

20200208_Spring AOP源码脉络分析

Spring AOP源码脉络分析 客户端通过getBean获取bean,实际是调用了 AbstractApplicationContext.getBean(String name) AbstractApplicationContextImpl.getBeanFactory().getBean(name) AbstractBeanFactory.doGetBean(String na...

ycoolq的博客 255

spring源码分析-AOP实现原理分析

1.简介2.如何实现3.源码分析(1)找入口(2)ProxyFactory类的getProxy(3)JdkDynamicAopProxy类的getProxy(ClassLoader classLoader)(4)JdkDynamicAopProxy类的invoke方法(5)Advised.getInterceptorsAndDynamicInterceptionAdvice()(6)getInte...

左耳听风的博客 935

【十四】Spring源码分析之AOP----JdkDynamicAopProxy代理对象invoke调用

一、简介 AOP源码分析主要分为5个篇章:前面4篇已经讲了 1.注册、实例化、初始化AnnotationAwareAspectJAutoProxyCreator 【十】Spring源码分析之AOP----注册、实例化、初始化AnnotationAwareAspectJAutoProxyCreator 2.扫描容器中的切面,创建PointcutAdvisor对象【十一】Spring源码分...

Sid小杰的博客 2088

百度大牛甩出Spring高阶手册全新演绎Spring 5新特性,原理+源码+实战三飞

Spring 大家都知道Spring是为了降低企业应用开发的复杂性而创建的。Spring不是创造轮子,而是使现有的轮子运转得更好的工具。它方便各种框架集成,降低了JavaEE开发的难度。它的重要性想必不用我多说了,作为一位身处于2020年的Java程序员,从源码到实际开发,Spring这一块是我们绕不过去的坎。 既然绕不过去,那就啃下他!对于Spring的学习,小编前段时间刚好在百度的一位大佬手上拿到一份Spring进阶宝典,看了之后,发现市面上的资料与其差距不止一点点!本着好东西就要拿出来分享的原则,

Java圈全能架构师的博客 1827

AOP如何实现及实现原理

概述: 最近在开发中遇到了一个刚好可以用AOP实现的例子,就顺便研究了AOP的实现原理,把学习到的东西进行一个总结。文章中用到的编程语言为kotlin,需要的可以在IDEA中直接转为java。 这篇文章将会按照如下目录展开: AOP简介 代码中实现举例 AOP实现原理 部分源码解析 1. AOP简介 相信大家或多或少的了解过AOP,都知道它是面向切面编程,在网上搜索可以找到很多的解释。这里我用...

weixin_34224941的博客 5576

spring源码解析

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33788244的博客 72

Spring框架源码解析

Spring框架源码解析 1. 项目基础介绍及主要编程语言 本项目名为“thinking-in-spring”,是一个专注于Spring框架源码解析的开源项目。主要采用Java语言开发,旨在帮助开发者深入理解Spring框架的内部机制和工作原理。通过该项目,读者可以系统地学习Spring框架的各个重要组成部分,包括但不限于IoC、AOP、数据源配置、事务管理等。 2. 项目的核心功能 IoC容...

gitblog_00219的博客 330

阿里P7:18小时讲完Spring源码解析整套笔记,拿走不谢

正文 开发人员面对突如其来的变化,无论在架构选型,还是在日常开发中,总会面临各种挑战和考验。唯有系统性地掌握 Spring Framework 编程思想、设计理念,以及具体的实现方式,方可游刃有余,以免进退失据。 作为 Spring 技术生态的基石,Spring Framework 无论在设计,还是在实现上,都是一个优秀的框架,许多细节方面是非常值得我们学习的,包括: Java 语言特性的运用,如反射、动态代理、枚举、泛型、注解、ARM,Lambda 语法等 设计思想和模式的实现,如 OOP、IoC、DD

lyl5454的博客 286

dubbo源码深度解析_这一份Spring源码解析PDF,阿里架构师直言:全网最深度解析!...

这分源码解析PDF,都给大家解析了哪些源码呢?IOC容器IoC容器在Web容器中的启动Spring JDBCSpring MVCSpring AOP获取Proxy ..Spring声明式事务处理Spring AOP中对拦截器调用的实现Spring驱动Hibernate的实现Spring Acegi框架鉴权的实现Spring Acegi框架授权的实现目录结构:目录结构:如果您想获取到这份最强最全源码...

weixin_39910043的博客 327

Spring源码速成,原来学习源码能这么容易

前言 一定不要放弃阅读源码 “源码”这两个字想必大家一看到是有人爱有人恨。后者在于:费时费力还复杂太考验耐心!但优秀的源码中有着多年积淀下来的精华,可以说阅读源码小到对源码所提供的功能上的使用更加熟练,大到使我们的程序设计更加完美优秀。身为程序员的我们为了不被时代淘汰,为了在同级中脱颖而出,肯定是不能停止学习的!为什么我们就不能做到通读源码?让多数人的短处成为我们的长处! 如何学? 想要掌握阅读源码的方法,看书站在巨人的肩膀上学习肯定是很好的一个途径,但光看书肯定枯燥无味,看书结合视频才是快速掌握阅

wdjnb的博客 423

深度解析Spring AOP核心原理与源码剖析:动态代理的幕后功臣

在当今企业级Java开发领域,Spring AOP(面向切面编程)作为Spring框架的核心模块之一,已经成为解决横切关注点问题的标准方案。2025年的最新Spring 6.x版本中,AOP机制经过持续优化,在保持原有设计精髓的同时,进一步提升了性能和扩展性。

zuiyuelong的博客 871
上一篇: spring生命周期与集成apollo原理分析(动态生效配置中心)
Kindle_code
博客等级 码龄12年 21粉丝 66原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值