Spring IOC容器初始过程

组件

Resource

spring中对资源文件的描述

public interface Resource extends InputStreamSource {
	// 获得资源文件流
	InputStream getInputStream() throws IOException;
	// 资源文件是否存在
	boolean exists();
	// 获得资源的url
	URL getURL() throws IOException;
	// 获得资源长度
	long contentLength() throws IOException;
	// 获得资源名
	String getFilename();
}	

ResourceLoader

资源加载器,ApplicationContext实现类都实现ResourceLoader接口,通过getResource获得资源

public interface ResourceLoader {
	// classpath的url前缀classpath:
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
	// 通过文件位置获得资源
	Resource getResource(String location);
}

BeanDefinitionRegistry

存放bean名称与BeanDefinition的映射,后续BeanFactory通过使用它来获得Bean

public interface BeanDefinitionRegistry extends AliasRegistry {
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);
}

AbstractBeanDefinition

表示xml中<bean>中数据

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
		implements BeanDefinition, Cloneable {
	// bean中class
	private volatile Object beanClass;
	// scope
	private String scope = SCOPE_DEFAULT;
	// 懒加载
	private Boolean lazyInit;
	// 类中属性值
	private MutablePropertyValues propertyValues;
	// 加载该bean的资源文件
	private Resource resource;
}

DefaultListableBeanFactory

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	// 忽略的依赖接口 beans标签使用default-autowire
	private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();
	// 忽略依赖类型
	private final Set<Class<?>> ignoredDependencyTypes = new HashSet<>();

	// 支持自动注入的关系映射
	private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

	// bean定义集合
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
	// 通过类型查找的所有bean名称
	private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
	// 单例bean缓存
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
	// 类型转换服务
	private ConversionService conversionService;
	// xml中定义的beanNames
	private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

}

AbstractRefreshableApplicationContext

//public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext 
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
	// 启动销毁IOC容器的同步器
	private final Object startupShutdownMonitor = new Object();
	// IOC容器允许Bean覆盖
	private Boolean allowBeanDefinitionOverriding;
	// IOC容器允许循环引用
	private Boolean allowCircularReferences

	// IOC容器活动标志
	private final AtomicBoolean active = new AtomicBoolean();
	// IOC容器关闭标志
	private final AtomicBoolean closed = new AtomicBoolean();
	// 启动日期
	private long startupDate;

	// IOC容器环境
	private ConfigurableEnvironment environment;
	// 持有的bean工厂
	private volatile DefaultListableBeanFactory beanFactory;
	// bean工厂处理器
	private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
	// 解析消息的策略接口,用于支持国际化资源
	private MessageSource messageSource;
	// 事件广播器
	private ApplicationEventMulticaster applicationEventMulticaster;
	
}

源码分析

基于ClassPathXmlApplicationContext分析

  1. IOC容器设置其启动日期和活动标志,以及执行属性源的任何初始化。
protected void prepareRefresh() {
	// 设置启动日期、活动关闭标志
	this.startupDate = System.currentTimeMillis();
	this.closed.set(false);
	this.active.set(true);	

	// 子类实现,初始属性资源
	initPropertySources();

	// 验证被标记为必须的属性是否存在
	getEnvironment().validateRequiredProperties();

	// 存储预刷新应用程序侦听器
	if (this.earlyApplicationListeners == null) {
		this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
	}
	else {
		// 将IOC容器的侦听器重置为刷新前状态
		this.applicationListeners.clear();
		this.applicationListeners.addAll(this.earlyApplicationListeners);
	}

	// 允许早期应用程序事件的集合
	this.earlyApplicationEvents = new LinkedHashSet<>();
}
  1. 创建beanFactory,同时加载配置文件中的beanDefinition
  • 如果容器已存在bean工厂则销毁并关闭,然后重新创建
  • 创建DefaultListableBeanFactory工厂,添加默认忽略接口BeanNameAware.class、BeanFactoryAware.class和BeanClassLoaderAware.class
  • 为工厂增加是否允许覆盖和重复引用
  • 根据配置文件初始化beanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	// 告诉子类刷新内部bean工厂
	refreshBeanFactory();
	return getBeanFactory();
}
// 调用AbstractRefreshableApplicationContext中的refreshBeanFactory
protected final void refreshBeanFactory() throws BeansException {
	// 如果容器已存在bean工厂则销毁并关闭
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		// 传入父工厂创建 DefaultListableBeanFactory
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		// 为工厂设置Id
		beanFactory.setSerializationId(getId());
		// 为工厂增加是否允许覆盖和重复引用
		customizeBeanFactory(beanFactory);
		// 根据配置文件加载beanFactory
		loadBeanDefinitions(beanFactory);
		this.beanFactory = beanFactory;
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}
  1. loadBeanDefinitions,创建XmlBeanDefinitionReader来读取xml配置beanFactory,两种读取,parseDefaultElement(读取默认import alias bean beans),parseCustomElement命名空间解析
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// 创建XmlBeanDefinitionReader来读取配置
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

	// 配置资源加载环境
	beanDefinitionReader.setEnvironment(this.getEnvironment());
	beanDefinitionReader.setResourceLoader(this);
	beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

	// 空方法,允许子类提供读取器的自定义初始化
	initBeanDefinitionReader(beanDefinitionReader);
	// 读取配置初始beanFactory
	loadBeanDefinitions(beanDefinitionReader);
}
// AbstractXmlApplicationContext,遍历configuration加载资源文件
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
	Resource[] configResources = getConfigResources();
	if (configResources != null) {
		reader.loadBeanDefinitions(configResources);
	}
	String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		reader.loadBeanDefinitions(configLocations);
	}
}
  1. 通过location获得资源文件
public Resource[] getResources(String locationPattern) throws IOException {	
	// 如果以 classpath*: 开头
	if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
		// 路径是否有?和*
		if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
			// a class path resource pattern
			return findPathMatchingResources(locationPattern);
		}
		else {
			// 在所有classpath路径下查找所有(包括jar中路径)
			return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
		}
	}
	else {
		// war包寻找*/,非war包寻找:位置
		int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
				locationPattern.indexOf(':') + 1);
		if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {			
			return findPathMatchingResources(locationPattern);
		}
		else {
			// 在classpath中找到一个资源文件
			return new Resource[] {getResourceLoader().getResource(locationPattern)};
		}
	}
}
  1. 准备BeanFactory以供在此上下文中使用
  • 类加载、el解析
  • 配置BeanPostProcessor完成Aware接口注入,如ApplicationContextAware、EnvironmentAware、ApplicationEventPublisherAware
  • 注册可解析依赖关系,使BeanFactory、ApplicationContext不在beans中也支持自动注入
  • 往容器中添加environment(总) systemProperties(系统属性,user.dir等) systemEnvironment(系统环境,如PATH等)三个对象
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 设置beanFactory使用的类加载器
	beanFactory.setBeanClassLoader(getClassLoader());
	// 为bean定义值中的表达式指定解析策略。默认spring el解析
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	// 添加一个PropertyEditorRegistrar以应用于所有bean创建过程
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// 使用上下文回调配置bean工厂,完成实现Aware接口类的注入工作
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	// beanFactory忽略依赖接口,作用方式:在beans标签使用default-autowire属性来注入依赖
	// ignoreDependencyType:自动装配时忽略指定接口或类的依赖注入
	// ignoreDependencyInterface:忽略该接口的实现类中和接口setter方法入参类型相同的依赖
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

	// 注册可解析依赖关系,使BeanFactory、ApplicationContext支持自动注入
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// Register early post-processor for detecting inner beans as ApplicationListeners.
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// 如果存在loadTimeWeaver则添加对应LoadTimeWeaverAwareProcessor,准备织入
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		// Set a temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}

	// 往容器中添加environment(总) systemProperties(系统属性,user.dir等) systemEnvironment(系统环境,如PATH等)三个对象
	if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
	}
}
  1. 空方法,子类扩展使用,在BeanFactory准备工作完成后做一些定制化的处理
// 结合BeanPostProcessor注入一些资源
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
  1. 调用被注册在IOC容器中的BeanFactoryPostProcessor的处理方法
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	// 调用已经注册的BeanDefinitionRegistryPostProcessor,依次调用IOC容器中实现PriorityOrdered、Ordered和普通的处理器
	// 调用已经注册的BeanFactoryPostProcessor,依次调用IOC容器中实现PriorityOrdered、Ordered和普通的处理器
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// 如果工厂存在loadTimeWeaver,则添加LoadTimeWeaverAwareProcessor
	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}
  1. 实例化并注册所有BeanPostProcessor类
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
	// 从IOC容器从获得所有BeanPostProcessor类型的Bean名称
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

	// 统计BeanProcessor数量,创建BeanPostProcessorChecker来打印日志
	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

	// 遍历postProcessorNames,区分实现PriorityOrdered、Ordered接口和普通的处理器
	List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
	List<String> orderedPostProcessorNames = new ArrayList<>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			priorityOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// 注册实现PriorityOrdered接口的BeanPostProcessor
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

	// 注册实现Ordered接口的BeanPostProcessor.
	List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
	for (String ppName : orderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		orderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, orderedPostProcessors);

	// 注册普通的BeanPostProcessor.
	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
	for (String ppName : nonOrderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		nonOrderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

	// 重新注册所有内部BeanPostProcessors,移动到列表尾部(先remove再add)
	sortPostProcessors(internalPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, internalPostProcessors);

	// 重新注册ApplicationListenerDetector,移动到列表尾部(先remove再add)
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
  1. 初始化MessageResource(用于解析消息的策略接口,支持此类消息的参数化和国际化。)
protected void initMessageSource() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	// 如果Bean工厂已存在messageSource类
	if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
		this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
		// 设置父MessageSource
		if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
			HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
			if (hms.getParentMessageSource() == null) {
				// Only set parent context as parent MessageSource if no parent MessageSource
				// registered already.
				hms.setParentMessageSource(getInternalParentMessageSource());
			}
		}
	}
	else {
		// 使用空的MessageSource
		DelegatingMessageSource dms = new DelegatingMessageSource();
		dms.setParentMessageSource(getInternalParentMessageSource());
		this.messageSource = dms;
		// MessageResource注册为单例
		beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
	}
}
  1. 初始化ApplicationEventMulticaster。如果上下文中没有定义,则使用SimpleApplicationEventMulticaster
  • 事件广播器,存放IOC容器中的监听,当事件被发布multicastEvent广播通知所有监听器
protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	// 如果工厂已有applicationEventMulticaster
	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
		this.applicationEventMulticaster =
				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
		···日志打印
	}
	// 没有则使用SimpleApplicationEventMulticaster
	else {
		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);	
		···日志打印
	}
}
  1. 空方法,子类扩展使用,加载子类中的其他特殊bean
protected void onRefresh() throws BeansException {
	// For subclasses: do nothing by default.
}
  1. 添加监听器到事件广播器中
protected void registerListeners() {
	// 注册静态指定的侦听器
	for (ApplicationListener<?> listener : getApplicationListeners()) {
		getApplicationEventMulticaster().addApplicationListener(listener);
	}

	// 注册BeanFactory中所有ApplicationListener类型的监听器
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	for (String listenerBeanName : listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
	}

	// 调用事件广播器处理早期应用事件
	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
	this.earlyApplicationEvents = null;
	if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
		for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
			getApplicationEventMulticaster().multicastEvent(earlyEvent);
		}
	}
}
  1. 完成BeanFactory初始化,初始化所有剩余的singletonBean详见
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// 为IOC容器配置类型转换
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}

	// 如果没有bean后处理程序,则注册一个默认的嵌入式值解析器,主要解析注解值
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}

	// 初始 LoadTimeWeaverAware 
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}

	// 停止使用临时加载器
	beanFactory.setTempClassLoader(null);

	// 冻结之前beandifinition的配置,configurationFrozen = true
	beanFactory.freezeConfiguration();

	// 实例化IOC容器中非懒加载的单例对象
	beanFactory.preInstantiateSingletons();
}
  1. 上下文刷新完毕处理
protected void finishRefresh() {
	// 清除资源缓存
	clearResourceCaches();

	// 为此上下文初始化生命周期处理器
	initLifecycleProcessor();

	// 将刷新完毕事件传播到生命周期处理器
	getLifecycleProcessor().onRefresh();

	// 推送上下文刷新完毕事件到相应的监听器
	publishEvent(new ContextRefreshedEvent(this));

	// Participate in LiveBeansView MBean, if active.
	LiveBeansView.registerApplicationContext(this);
}

总结

  1. 构造方法中获得ResourcePatternResolver和环境变量
  2. 设置资源位置
  3. refresh
    3.1 prepareRefresh date active,requiredProperties校验 早期监听
    3.2 obtainFreshBeanFactory 获得defaultListBeanFAcotry 设置SerializationId 可覆盖 可循环依赖 解析xml import alias bean 命名空间解析 资源加载 * 和 不带*
    3.3 prepareBeanFactory 类加载、el表达式、资源属性编辑器 BeanPostProcessorAware初始化前配置spring资源,忽略依赖接口,可解析依赖不用直接在bean中定义,环境变量,织入
    3.4 postProcessBeanFactory 子类实现,加载一些额外资源,如ServletContext
    3.5 invokeBeanFactoryPostProcessor 调用BeanDefinitionRegistryPostProcessor->BeanFactoryPostProcessor的方法,Priority、Order、普通顺序执行 织入
    3.6 registerBeanPostProcessors 注册Bean初始回调
    3.7 initMessageResource 初始国际化资源
    3.8 initApplicationEventMulticaster 初始事件广播器
    3.9 onRefresh 子类实现,加载特殊bean
    3.10 registerListeners 在事件广播器中注册监听器
    3.11 finishBeanFactoryInitialization 类型转换 LoadTimeWeaverAware类初始 冻结配置 完成单例bean初始化
    3.12 finishRefresh 初始生命周期处理器 发布ContextRefreshedEvent事件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值