Spring3.x源码分析(5)-bean加载2-创建bean实例

本文深入剖析Spring3.x框架中Bean的加载机制,重点讲解singleton、prototype及其他scope类型的Bean实例创建过程。从源码层面解读Bean实例化、属性填充、初始化及销毁等关键环节,揭示Spring框架内部Bean管理的核心原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring3.x源码分析(5)-bean加载

《Spring源码深度解析》spring-framework-reference

bean的加载

接下来分析上一张跳过的内容创建bean实例,分别针对singleton,prototype,其他scope类型bean进行创建。


创建singleton实例

创建singleton的入口代码逻辑如下:

if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
        //重写接口方法
        public Object getObject() throws BeansException {
            try {
                return createBean(beanName, mbd, args);
            } catch (BeansException ex) {
                destroySingleton(beanName);
                throw ex;
            }
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

getSingleton(beanName ,objectFactory)

//org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	
	protected static final Object NULL_OBJECT = new Object();
	
	/** 被抑制的异常集合: 不抛出的异常Set*/
	private Set<Exception> suppressedExceptions;
	
	//标识当前容器是否正在销毁singletons
	private boolean singletonsCurrentlyInDestruction = false;
	
	/**缓存 singleton objects: bean name --> bean instance */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

	/** 排除创建bean列表*/
	private final Map<String, Boolean> inCreationCheckExclusions = new ConcurrentHashMap<String, Boolean>(16);
	
	/** 当前正在创建bean列表 */
	private final Map<String, Boolean> singletonsCurrentlyInCreation = new ConcurrentHashMap<String, Boolean>(16);
	
	
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "'beanName' must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				
				//1. 检测当前容器是否正处于销毁singletons装填
				if (this.singletonsCurrentlyInDestruction) {
					//如果当前正处于 销毁singletons 阶段,在此阶段创建singleton 会抛出异常.....
					throw new BeanCreationNotAllowedException(beanName,"xxx...");
				}
			
				//2.创建前检查,将beanName注册到当前创建bean集合中
				beforeSingletonCreation(beanName);

				//省略suppressedExceptions.....
				try {
					//3.最终是通过 singletonFactory.getObject();来进行对象创建
					singletonObject = singletonFactory.getObject();
				}  finally {
					//4.创建后检测,,将beanName从当前创建bean集合中移除
					afterSingletonCreation(beanName);
				}
				
				//5.创建singleton
				addSingleton(beanName, singletonObject);
			}
			
			return (singletonObject != NULL_OBJECT ? singletonObject : null);
		}
	}
	
	//2.Singleton创建前检测
	protected void beforeSingletonCreation(String beanName) {
		// 排除创建bean列表 不包含beanName
		// 将beanName设置为 当前正在创建缓存 != null 的含义:表示当前singletonsCurrentlyInCreation 不包含beanName
		if (!this.inCreationCheckExclusions.containsKey(beanName) &&
				this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}
	
	//4.Singleton创建后检测
	protected void afterSingletonCreation(String beanName) {
		// 排除创建bean列表 不包含beanName
		// 将beanName从正在创建缓存中移除,
		// 如果singletonsCurrentlyInCreation.remove(beanName) == false,则会触发异常
		// 如果== true,则正常。 此时表示当前创建列表中存在 beanName -> true的记录。 即当前beanName正在创建中。
		if (!this.inCreationCheckExclusions.containsKey(beanName) &&
				!this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}
	
	//5.创建singleton
	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			// singletonObjects缓存添加  beanName
			this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
			
			//从singletonFactories , earlySingletonObjects 缓存中移除。
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			
			// registeredSingletons缓存添加  beanName
			this.registeredSingletons.add(beanName);
		}
	}
}

分析上述代码,最终bean的创建的核心代码是调用了//3. singletonFactory.getObject();来完成的,

而这段代码的逻辑中的singletonFactory是有方法入参传入的,最终创建bean的逻辑,是交由createBean(beanName, mbd, args);完成的。

上述代码流程如下图:在这里插入图片描述


createBean(beanName, mbd, args);

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) {

    // 确保bean class 在此处已经解析了。
    resolveBeanClass(mbd, beanName);
    
    //1. 设置MethodOverride的 重载标识。
    mbd.prepareMethodOverrides();

    //2.执行BeanPostProcessors,当执行结果返回bean != null时,则程序短路,不在进行后续的创建操作
    Object bean = resolveBeforeInstantiation(beanName, mbd);
    if (bean != null) {
        return bean;
    }
	
    //最终交由doCreateBean(),来创建bean....
    Object beanInstance = doCreateBean(beanName, mbd, args);
    return beanInstance;
}

1. mbd.prepareMethodOverrides()

//org.springframework.beans.factory.support.AbstractBeanDefinition

public void prepareMethodOverrides() throws BeanDefinitionValidationException {
	//获取配置的 <lookup-method > ,<replaced-method > 方法清单
	MethodOverrides methodOverrides = getMethodOverrides();
	if (!methodOverrides.isEmpty()) {
        //for-each 遍历所有的 overrides 方法..
		for (MethodOverride mo : methodOverrides.getOverrides()) {
			prepareMethodOverride(mo);
		}
	}
}

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
	//计算同名方法的个数(是否重载)
	int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
	if (count == 0) {
		//如果为0,则说明没有该名称的方法,与上面逻辑不符,抛出异常
		throw new BeanDefinitionValidationException(
				"Invalid method override: no method with name '" + mo.getMethodName() +
				"' on class [" + getBeanClassName() + "]");
	} else if (count == 1) {
		//如果只有1个同名方法, 说明该方法没有被重载
		mo.setOverloaded(false);
	}	
}

2. resolveBeforeInstantiation

//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
	Object bean = null;
	//默认为null,第一次都能进入if{}语句块
	if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
		
		//synthetic:合成的,用户定义的bean都为false,AOP自动创建的会为true
		//hasInstantiationAwareBeanPostProcessors()  --- 注
		if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			//1.
			bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);
			if (bean != null) {
				//2.
				bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
			}
		}
		mbd.beforeInstantiationResolved = (bean != null);
	}
	return bean;
}

//1. 执行 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization()
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		//遍历所有的BeanPostProcessor,寻找到InstantiationAwareBeanPostProcessor类型
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			
			//执行postProcessBeforeInstantiation方法,并找到第一个执行结果不为空的结果,返回
			Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
			if (result != null) {
				return result;
			}
		}
	}
	return null;
}

//2. 执行所有BeanPostProcessor.postProcessAfterInitialization()
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) {
	Object result = existingBean;
	for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
		//遍历所有的BeanPostProcessor,执行postProcessAfterInitialization方法,当执行结果为null时,不再往下执行.
		result = beanProcessor.postProcessAfterInitialization(result, beanName);
		if (result == null) {
			return result;
		}
	}
	return result;
}

注1

之前文章介绍了BeanPostProcessor相关知识,当使用factory.addBeanPostProcessor(processor)时,

如果存在processor是InstantiationAwareBeanPostProcessor类型的时候,则设置hasInstantiationAwareBeanPostProcessors为true;

在这里插入图片描述


doCreateBean

最终bean的创建委托给doCreateBean()来完成.

//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

/** 未完成FactoryBean实例缓存: FactoryBean name --> BeanWrapper */
private final Map<String, BeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<String, BeanWrapper>(16);

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {

		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			//从获取缓存中 未完成FactoryBean
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			//1. 如果instanceWrapper为空,则通过createBeanInstance创建BeanWrapper,并返回
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		
		//获取bean, beanType
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				//2. 执行 MergedBeanDefinitionPostProcessors , 执行完成之后将标识置为true
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				mbd.postProcessed = true;
			}
		}

		// 此时bean刚刚创建完成,还没有完成初始化以及属性的注入等。
		//判断是否需要 提前曝光此bean,用来解决在singleton循环依赖的问题
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));	
		if (earlySingletonExposure) {
             //3.
			//3.1 避免后期循环依赖,可以在bean初始化完成前将创建示例的ObjectFactory假如缓存
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				public Object getObject() throws BeansException {
                     //3.2 
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

		Object exposedObject = bean;
		
		//4.从mbd获取属性信息,填充到instanceWrapper中的 bean实例。
		populateBean(beanName, mbd, instanceWrapper);
		if (exposedObject != null) {
			//5.执行初始化方法
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		
    	//6.
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
            //earlySingletonReference只有在检测到有循环依赖的情况下才不为空
			if (earlySingletonReference != null) {
                 //if true,表明exposedObject没有在初始化方法中被改变,即没有被增强
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                     //所有依赖该bean的集合
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                     //检测依赖
					for (String dependentBean : dependentBeans) {
                         //如果依赖beanName 的 bean先一步创建完成,即alreadyCreated.contains(dependentBean),则返回false,取 "非"后 为true
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                              //添加 出现错误依赖的dependentBean
							actualDependentBeans.add(dependentBean);
						}
					}
                    	
                     //因为bean创建后,它所依赖的bean也一定已经创建了
                     //但是如果actualDependentBeans不为空,则说明bean所依赖的bean并没有创建完,则说明存在循环依赖
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,"xxxxxx....");
					}
				}
			}	
		}

		//7. 注册销毁方法...
		registerDisposableBeanIfNecessary(beanName, bean, mbd);

		return exposedObject;
	}

1.createBeanInstance

分三种方式创建bean实例

1.1 instantiateUsingFactoryMethod 工厂类创建

最终调用ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);来完成创建.

创建的大致步骤如下,后续会专门针对此类来进行详细分析

  • 创建bw = new BeanWrapperImpl();
  • 初始化beanFactory.initBeanWrapper(bw);
  • 判断是否为静态工厂方法:isStatic
  • 构造函数参数的确定argsToUse
  • 根据isStatic和方法名称获取候选方法清单
  • 确定构造函数
  • 根据实例化策略实例化bean.(如果有动态覆盖则需要使用cglib动态代理,如果没有,则直接使用反射即可)

1.2 autowireConstructor-带参数的实例化

最终调用ConstructorResolver(this).autowireConstructor(beanName, mbd, explicitArgs);来完成创建.

步骤参上上述instantiateUsingFactoryMethod

1.3 instantiateBean-不带参数的实例化

没有上述两种方法来确定构造函数和参数的复杂逻辑,直接调用最后一步:

  • 根据实例化策略实例化bean.

2.applyMergedBeanDefinitionPostProcessors

//2.执行MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(),执行bean定义的合并
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName){
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof MergedBeanDefinitionPostProcessor) {
			MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
			bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
		}
	}
}

3.addSingletonFactory

//3.1 addSingletonFactory
protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
	synchronized (this.singletonObjects) {
		//必须满足 singletonObjects不包含beanName, 即beanName没有创建完成
		if (!this.singletonObjects.containsKey(beanName)) {
			//singletonFactories添加缓存
			this.singletonFactories.put(beanName, singletonFactory);
			
			//earlySingletonObjects移除缓存
			this.earlySingletonObjects.remove(beanName);
			
			//registeredSingletons添加缓存
			this.registeredSingletons.add(beanName);
		}
	}
}

//3.2
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                     //AOP通过此方法将advice织入bean中
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
					if (exposedObject == null) {
						return exposedObject;
					}
				}
			}
		}
		return exposedObject;
	}

4.populateBean – 属性填充

//4. 填充属性
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
	PropertyValues pvs = mbd.getPropertyValues();

	//判断条件省略.....

	//是否继续属性填充标识
	boolean continueWithPropertyPopulation = true;
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				
				//通过构造函数或工厂方法实例化bean之后执行操作,但是在Spring属性入口(来自显式属性或自动装配)之前发生。
				//如果返回false,随后的InstantiationAwareBeanPostProcessor以及Spring属性注入都会被skipped
				if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					continueWithPropertyPopulation = false;
					break;
				}
			}
		}
	}

	if (!continueWithPropertyPopulation) {
		return;
	}

	if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
			mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
			//4.1 按照名称填充属性 -- 提取依赖的bean,并统一装入newPvs
			autowireByName(beanName, mbd, bw, newPvs);
		}

		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			//4.2 按照类型填充属性 -- 提取依赖的bean,并统一装入newPvs
			autowireByType(beanName, mbd, bw, newPvs);
		}

		pvs = newPvs;
	}

	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

	if (hasInstAwareBpps || needsDepCheck) {
		//剔除 bw属性中 且在 ignoredDependencyTypes 类型的参数;
		PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		if (hasInstAwareBpps) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					//InstantiationAwareBeanPostProcessor.postProcessPropertyValues(), 典型的应用如 @Required 注解属性进行验证
					pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); 
					if (pvs == null) {
						return;
					}
				}
			}
		}
		if (needsDepCheck) {
			//再次验证
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}
	}
	
	//将MutablePropertyValues 应用到BeanWraper中
	applyPropertyValues(beanName, mbd, bw, pvs);
}

5.5. 执行初始化方法

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
	//5.1.执行Aware接口方法
	invokeAwareMethods(beanName, bean);

	Object wrappedBean = bean;	
	if (mbd == null || !mbd.isSynthetic()) {
		//5.2. BeanPostProcessor.postProcessBeforeInitialization()
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}
	
	//5.3 执行init方法
	invokeInitMethods(beanName, wrappedBean, mbd);
	
	if (mbd == null || !mbd.isSynthetic()) {
		//5.4. BeanPostProcessor.postProcessAfterInitialization
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	return wrappedBean;
}
	
//5.1 执行aware接口方法
private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof BeanNameAware) {
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
		}
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

//5.3. 执行各渠道定义的init-method
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
			 {
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        //如果实现了InitializingBean接口, 则执行  afterPropertiesSet();
        ((InitializingBean) bean).afterPropertiesSet();
    }

    if (mbd != null) {
        String initMethodName = mbd.getInitMethodName();
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
            //执行bean定义的 init-method 属性定义的方法
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

5.6. 注册销毁方法

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
	AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
	// requiresDestruction(bean, mbd)最终调用逻辑
	//(bean != null && (bean instanceof DisposableBean || mbd.getDestroyMethodName() != null || hasDestructionAwareBeanPostProcessors()));
	if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
		if (mbd.isSingleton()) {
			//单例模式下注册:会处理实现DisposableBean接口 || 配置destroy-method || 声明有DestructionAwareBeanPostProcessors 的bean.
			registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
		}
		else {
			// A bean with a custom scope...
			Scope scope = this.scopes.get(mbd.getScope());

			//SimpleThreadScope此方法是空实现, 需要手动设置,执行callback
			scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));				
		}
	}
}

在这里插入图片描述



创建prototype实例

与创建singleton实例的总体流程大致相同,不在赘述。

创建其他scope实例

//org.springframework.beans.factory.support.AbstractBeanFactory
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
						public Object getObject() throws BeansException {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						}
					});


//org.springframework.context.support.SimpleThreadScope
public Object get(String name, ObjectFactory objectFactory) {
    Map<String, Object> scope = threadScope.get();
    Object object = scope.get(name);
    if (object == null) {
        object = objectFactory.getObject();
        scope.put(name, object);
    }
    return object;
}
					
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值