Spring 容器的创建及刷新

【项目实战】从0开始入门Spring Boot源码 - Spring Boot的启动流程源码,涵盖环境准备、上下文创建、容器刷新、自动配置及扩展点(如监听器、Runners)的执行。 SpringBoot的启动流程源码涉及多个关键阶段,SpringBoot的启动流程通过方法串联,涵盖环境准备、上下文创建、容器刷新、自动配置及扩展点(如监听器、Runners)的执行。其核心在于利用Spring框架的刷新机制,集成内嵌服务器和条件化配置,简化了传统Spring应用的部署与配置复杂度。 阅读详情
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            // 刷新前的预处理
            // initPropertySource() 初始化一些属性;子类自定义个性化的属性设置方法
            // getEnvironment().validateRequiredProperties();校验属性合法等
            // earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>(); 保存容器中的一些早期时间
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            // 获取 BeanFactory
            // refreshBeanFactory 刷新BeanFactory
            // 创建了一个 this.beanFactory = new DefaultListableBeanFactory();
            // 设置序列化ID
            // getBeanFactory();返回 GenericApplicationContext 创建的 BeanFactory 对象
            // 将 BeanFactory【DefaultListableBeanFactory】返回
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            // BeanFactory 的预准备工作(BeanFactory 进行一些设置)
            // 设置 BeanFactory的类加载器、支持表达式解析器...
            // 添加部分的 BeanPostProcessor【ApplicationContextAwareProcessor】
            // 设置忽略自动装配的接口 Environment、EmbeddedValueResolverAware、xxx
            // 注册可以解析的自动装配:我们能直接在任何组件中自动注入:BeanFactory、ResourceLoader、ApplicationEventPulisher、ApplicationContext
            // 添加 BeanPostProcessor【ApplicationListenerDetector】
            // 添加编译时的AspectJ
            // 给BeanFactory注册 environment【ConfiguravleEnvironment】、systemProperties【Map<String,Object>】、systemEnvironment【Map<String,Object>】
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                // postProcessBeanFactory(beanFactory);BeanFactory 准备工作完成后进行的后置处理工作
                // 子类通过重写 在BeanFactory串讲并预准备完成以后做进一步设置
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                // 执行 BeanFactory 的后置处理器
                // 在 BeanFactory 标准初始化之后执行的
                // 两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryProcessor
                // 执行 BeanFactoryPostProcessor
                // 获取所有的 BeanDefinitionRegistryPostProcessor
                // 先执行实现 PriorityOrdered 优先级接口的 BeanDefinitionRegistryPostProcessor;postProcessor.postProcessBeanDefinitionRegistry(registry)
                // 在执行实现利润 Orderd 顺序接口的BeanDefinitionRegistryPostProcessor;postProcessor.postProcessBeanDefinitionRegistry(registry)
                // 最后执行没有实现任何优先级或者顺序接口的 顺序接口的 BeanDefinitionRegistryPostProcessor
                // 再执行 BeanFactoryPostProcessor 
                // 获取所有的 BeanFactoryPostProcessor
                // 先执行实现 PriorityOrdered 优先级接口的 BeanFactoryPostProcessor;postProcessor.postProcessBeanFactory(beanFactory);
                // 在执行实现利润 Orderd 顺序接口的 BeanFactoryPostProcessor;postProcessor.postProcessBeanFactory(beanFactory);
                // 最后执行没有实现任何优先级或者顺序接口的 顺序接口的 BeanFactoryPostProcessor
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 注册 BeanPostProcessor(Bean的后置处理器)【拦截 Bean 的创建过程】
                // 不同类型的 BeanPostProcessor 在Bea 创建前后的执行时机是不一样的
                // DestructionAwareBeanPostProcessor
                // InstantiationAwareBeanPostProcessor
                // SmartInstantiationAwareBeanPostProcessor
                // MergedBeanDefinitionPostProcessor【internalPostProcessors】
                // 获取所有的 BeanPostProcessor 后置处理器都可以通过 PriorityOrderd 和 Orderd 接口来执行优先级
                // 先注册 PriorityOrderd 优先级接口的BeanPostProcessor;BeanFactory.addBeanPostProcessor(postProcessor)
                // 在注册 Orderd 接口的
                // 最后注册没有实现任何优先级接口的
                // 最终注册 MergedBeanDefinitionPostProcessor
                // 注册一个 ApplicationListenerDetector;来在 Bean 创建完成后检查是否是 ApplicationListener
                // 如果是 applicationContext.addApplicationListener((ApplicationListener<?>) bean);
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                // 初始化MessageSource组件(做国际化功能:消息绑定,消息解析)
                // 获取 BeanFactory
                // 查询容器中是否有 id 为 messageSource ,类型是 MessageSource 的组件
                // 如果有赋值给 messageSource,如果没有就创建一个 DelegatingMessageSOurce;
                // MessageSource:取出国际化配置文件中的某个 key 值;能按照区域信息获取
                // 把创建好的 MessageSource 注册到容器中,以后获取国际化配置文件的值的时候,可以自动注入 MessageSource 使用 getMessage() 方法
                // BeanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME,this.messageSource);
                initMessageSource();

                // Initialize event multicaster for this context.
                // 初始化事件派发器
                // 获取 BeanFactory
                // 从BeanFactory中获取 applicationEventMulticaster 的 ApplicationEventMulticaster
                // 如果没有配置,创建一个 SimpleApplicationEventMulticaster
                // 将创建的 ApplicationEventMulticaster 增加到 BeanFactory中,以后其他组件直接祖丁注入
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                // 留给子容器(子类) 
                // 子类重写这个方法,在容器刷新的时候可以自定义逻辑
                onRefresh();

                // Check for listener beans and register them.
                // 给容器中将所有项目的 ApplicationListener 注册进来
                // 从容器中拿到所有的 ApplicationListener
                // 将每个监听器增加到事件派发器中getApplicationEventMulticaster.addApplicationListenerBean(listenerBeanName);
                // 派发之前步骤产生的实践
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                // 初始化所有剩下的单实例 bean
                // BeanFactory.preInstantiateSingletons(); 初始化剩下的单实例 bean
                // 获取容器中的所有 bean ,一次进行初始化和创建对象,
                // 获取bean 的定义信息:RootBeanDefinition
                // Bean 不是抽象的,是单实例的,不是懒加载的 
                // 判断是否是工厂 Bean;是否实现 FactoryBean 接口的 Bean
                // 不是工厂 bean 使用 getBean() 创建对象
                // getBean(beanName); ioc.getBean();
                // doGetBean(name,null,null,false);
                // 先获取缓存中保存的单实例Bean,如果能获取到说明这个 Bean 之前被创建国(所有创建国的单实例 Bean 都会被缓存起来) 从 private final Map<String, Objec> singletonObjects = new ConcurrentHashMap<String, Object>(256); 中获取
                // 缓存中获取不到,开始 Bean 的创建流程
                // 标记当前 bean 已经被创建
                // 获取 Bean 的定义信息
                // 获取当前 Bean 依赖的其他 Bean;如果有 按照 getBean() 把依赖的 Bean 先创建出来
                // 启动单实例 Bean  的创建流程
                // ceateBean(beanName, mbd, args);
                // Obejct bean = resolveBeforeInstantiation(beanName, mbdToUse); 让 BeanPostProcessor 先拦截返回代理对象 InstantiationAwareBeanPostProcessor 提前执行 触发 postProcessBeforeInstantiation(); 如果有返回值 在触发 postProcessAfterInstantiation();
                // 如果 InstantiationAwareBeanPostProcessor没有返回代理对象 调用 Object beanInstance = doCreatBean(beanName, mbdToUse, args);
                // 【创建 Bean 实例】 createBeanInstance(beanName, mbd, args);
                // 李瑞勇工厂方法或对象构造器创建 bean 实例
                // applyMergedBeanDefinitionProcessors(mbd, beanType, beanName);
                // 调用 MergedBeanDefinitionPostProcessor 的postProcessMergedBeanDefinition(mbd, beanType, beanName);
                // 【Bean 属性赋值】 populatBean(beanName, mbd, instanceWrapper); 
                // 赋值之前 
                // 拿到 InstantiationBeanPostProcessor 后置处理器 执行 postProcessAfterInstantiation();
                // 拿到 InstantiationBeanPostProcessor 后置处理器 执行 postProcessPropertyValues();
                // 应用 Bean 属性利用 setter方法等赋值 applyPropertyValues(beanName, mbd, bw, pvs);
                // 【Bean 初始化】 initializeBean(beanName, exposedObject, mbd);
                // 【接口的方法】invokeAwareMethods(beanName, bean); 执行 ***Aware  BeanNameAware\BeanClassLoaderAware\BeanFactoryAware
                // 【执行后置处理器初始化之前】applyBeanPostProcesBeforeInitialization(wrapped, beanName); BeanPostProcessor.postProcessBeforeInitialization();
                // 【执行初始化方法】 invokeMethods(beanName, wrappedBean, mbd);
                // 是否是 InitializingBean 接口的实现;执行接口规定的初始化;
                // 是否是 自定义初始化方法
                // 【执行后置处理器初始化之后】applyBeanPostProcesAfterInitialization(wrapped, beanName); BeanPostProcessor.postProcessAfterInitialization;
                // 注册 Bean 的销毁方法
                // addSingleton() 将已创建的bean 添加到缓存中 singletonObjects
                // 检查所有的 Bean 是否是 SmartInitializingSingleton 接口的,如果是就会执行 afterSingletonsInstantiated()
finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                // 完成 BeanFactory 的初始化创建工作
                // inITLifecycleProcessor();初始化和生命周期有关的后置处理器。
                // 如果有实现 LifecycleProcessor 的实现类,可以拦截 BeanFactory 的生命周期 void onRefresh(); void onClose();
                // 如果没有,创建一个默认的 new DefaultLiftcycleProcessor();
                // 拿到生命周期后置处理器,执行 onRefresh();
                // publishEvent(new ContextRefreshedEvent(this)); 发布容器刷新完成事件
                // LiveBeansView.registerApplicationContext(this);
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

总结:

/*
1) Spring 容器在启动的时候,贤惠保存所有注册进来的 Bean 定义信息
    1)xml注册 bean;<bean>
    2) 注解注册Bean; @Service @Component @Bean
2) Spring 容器会在何时的实际创建这些 Bean
    1) 用到这个 bean 的时候,利用 getBean 创建 bean;创建好以后保存到容器中
    2) 同意创建剩下的所有 bean 的时候,finishBeanFactoryInItialization()
3) 后置处理器
    每一个 bean 创建完成,都会使用各种后置处理器进行处理,来增强 bean 的功能
    AutowiredAnnotationBeanPostProcessor 处理自动注入
    AnnotationAwareAspectJAutoProxyCreator 来做 AOP 功能
    AsyncAnnotationBeanPostProcessor 异步
4) 事件驱动模型
    ApplicationListener 事件监听
    ApplicationEventMulticaster 事件派发
*/

 

Dynamics CRM证书更换   Dynamics CRM产品一般有两种认证方式。第一种是基于声明的内部访问也就是无证书单纯用账号密码验证。第二种就是联合身份认证,需要安装网站证书。   对于联合身份认证的情况因为需要安装证书,而且证书是有一个一年的有效期,所以运维人员每年都需要进行证书更换的操作。以下就是更换证书的方法及过程。 证书根据申请方式一般也分两种,第一种是自建证书,这种证书是没有机构认证的所以安装上之后网站因为没... 阅读详情

相关推荐

Cursor 使用教程(2025年更新版)

官方Cursor详细使用教程在“扩展学习”

我是赛博AI Lewis 7082

Java刷新bean重新加载bean 上下文 刷新bean

@Autowired private ApplicationContext applicationContext; // 可以为接口或者业务方法被调用 public void reloadInstance(){ //获取上下文 DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();

Z_hhhha的博客 4786

堆内存管理核心逻辑 超详细复习笔记

本文详细解析了堆内存管理的核心逻辑,包括初始化、分配和释放三个关键环节。系统通过全局堆管理结构体和链表机制实现动态内存管理:初始化时标记整块内存为空闲;分配时遍历链表查找合适空闲块并进行分割;释放时定位内存块头并重新标记为空闲,支持相邻块合并以减少碎片。文章对比了链表式管理和线性分配的优缺点,指出链表式更灵活但实现复杂,线性分配简单但无法释放。最后总结了常见错误(如指针回推错误、碎片问题)和扩展知识(不同内存管理算法)。这套机制是理解嵌入式系统和RTOS内存管理的基础。

2502_92009732的博客 1199

Spring IOC容器刷新BeanFactory(XML配置方式)

Spring IOC容器刷新BeanFactory 前言     Spring IOC容器刷新BeanFactory是一个很复杂的过程,本文将基于XML配置的方式展开分析一下Spring IOC容器刷新BeanFactory的过程,如有误还请指出。 告诉子类刷新内部BeanFactory public void refresh() throws BeansException, IllegalStateException { synchronized (this.startup

qq_31279701的博客 349

Linux基础——“C语言高级编程” C语言中的细节你真的知道吗?

文章目录GCC简介 GCC简介 gcc 所支持后缀名解释 .c c原始程序 .C / .cc /.cxx C++原始程

weixin_44278698的博客 2511

Vivado实战:AXI转PCIe IP核配置全流程(含性能优化技巧)

本文详细介绍了在Vivado环境中配置AXI转PCIe IP核的全流程,包括工程准备、IP核参数设置、BAR空间配置、中断系统优化以及TLP传输效率提升等关键步骤。特别分享了经过验证的性能优化技巧,帮助开发者显著提升PCIe链路的吞吐量和稳定性,适用于视频采集、高速数据记录等应用场景。

weixin_30892037的博客 552

四、SpringBoot源码学习--容器的刷新-加载bean

学习spring boot源码,spring boot的bean的加载

kai6865599的博客 2369

路径跟踪 | 图解纯追踪算法Pure Pursuit(附ROS C++/Python/Matlab仿真)

纯追踪算法(Pure Pursuit)参考了人类驾驶行为,其基本思想是在待跟踪路径上设置预瞄点(goal-ahead),通过简单的几何方法驱动机器人跟踪预瞄点直至抵达目标位置.本文详细推导纯追踪算法的理论原理及其变种——自适应纯追踪算法(APP)和规范化纯追踪算法(RPP),并提供ROS C++/Python/Matlab三种仿真实现加深理解

FRIGIDWINTER的博客 8408

Spring注解驱动开发-扩展原理之002-Spring容器刷新第二步-obtainFreshBeanFactory()

2、obtainFreshBeanFactory()获取BeanFactory /** * Tell the subclass to refresh the internal bean factory. * @return the fresh BeanFactory instance * @see #refreshBeanFactory() * @see #getBeanFactory() */ protected ConfigurableListableBeanFact.

Choco1ove的博客 251

File Load Error for Untitled.ipynb Unhandled error 解决方案

本文主要介绍了File Load Error for Untitled.ipynb Unhandled error 解决方案,希望能对使用jupyter notebook的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 1万+

北斗导航 | 接收机自主完好性监测(RAIM)算法近三年研究现状总结(2022-2025)

近三年RAIM算法已从传统的单故障检测演进为多星座协同、智能融合的复杂系统,在航空、自动驾驶等安全关键领域实现规模化应用。未来需重点突破城市复杂环境适应性和标准化体系建设,推动技术从"可用"向"可信"跨越。

尘世冰封的专栏 439

Spring源码系列(三)——容器的刷新(上)

Spring源码系列(三)——容器的刷新(上)

scorpio的博客 950

双目深度相机--10.双目视觉的主要步骤讲解分析

双目视觉技术通过模拟人眼原理,利用两个相机从不同视角采集图像,实现三维坐标计算。其核心流程包括:1)系统标定,消除相机畸变并建立坐标映射关系;2)图像同步采集与预处理;3)立体匹配,寻找左右图像对应点;4)基于视差图的深度计算;5)三维重建生成点云或网格模型;6)结果应用如目标测距、三维建模等。关键技术难点在于精确标定和准确匹配,这两步直接影响最终深度计算的精度。该技术广泛应用于自动驾驶、工业检测、VR等领域,实现了从二维图像到三维空间的精准转换。

AIoT深度探索者 | 嵌入式系统架构师 深耕物联网(IoT)与人工智能(AI)融合技术,聚焦​​边缘计算、图像开发、低功耗通信协议​​,致力于智能硬件,关注我获取最新技术文章信息与海量资源~ 625

Spring容器的refresh()【创建刷新】

Spring容器的refresh() 1.Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息: 1)、xml注册bean;<bean> 2)、注解注册Bean;@Service、@Component、@Bean、xxx 2.Spring容器会合适的时机创建这些Bean: 1)、用到这个bean的时候;利用getBean创建bean;创建好以...

weixin_42679286的博客 591

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Spring容器的创建刷新过程

Spring容器的创建刷新过程 以AnnotionConfigApplicationContext为例,在new一个AnnotionConfigApplicationContext的时候,其构造函数内就会调用父类的refresh方法 public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { ...

weixin_33721427的博客 168

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Spring boot源码深入学习(六) | 容器的创建,准备,刷新,启动

回顾 上一篇 学习了prepareEnvironment准备环境: 1.初始化环境 2.配置环境 3.加载配置文件.通过ApplicationEnvironmentPreparedEvent事件发布,执行对应的监听器事件 4.绑定环境到SpringApplication 下面学习一下容器的创建,准备,刷新,启动。 首先看一看核心run方法流程回顾一下: public ConfigurableApplicationContext run(String... args) { // 实例化一个stopWat

qq_38425803的博客 720

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

从Spring容器刷新过程中的创建Bean阶段来说说Bean的生命周期

从Spring容器刷新过程中的创建Bean阶段来说说Bean的生命周期 我们所说的Bean的生命周期指的是从Bean的创建、初始化、使用Bean、销毁的整个过程。而IOC容器就是负责管理Bean的整个生命周期。实际上Bean的生命周期在容器启动的时候就已经开始了,严格来说,你可以认为容器启动时,从注解配置读取器读取标有注解的类,转换为BeanDefinition对象时,Bean的生命周期就已经开始了。打个比方,小宝宝的生命的起点,并不是说从出生落地开始算的,而是从妈妈肚子里面,基本上可以算是生命已经开始了。

qq_39794062的博客 659

【Spring源码】SpringBoot中Spring容器bean的创建与刷新

spring源码:SpringBoot中Spring容器bean的创建与刷新

See_Star的博客 2428

【Spring源码】 Spring ioc的创建之刷新容器(四)

相关文章 【Spring源码】Spring ioc创建的流程(一) 【Spring源码】 Spring ioc的创建之刷新容器(二) 【Spring源码】 Spring ioc的创建之刷新容器(三) 文章目录相关文章一. 刷新容器的源码 一. 刷新容器的源码 @Override public void refresh() throws BeansException, IllegalS...

Not_a_penny_to_name的博客 283

Spring容器的refresh()[创建刷新]

学习视频:视频链接[尚硅谷的雷神] 视频学习资料评论区有 Spring容器的refresh()[创建刷新]; 1、prepareRefresh();刷新前的预处理 1)、initPropertySources();初始化一些属性设置;子类自定义一些属性设置方法 2)、getEnvironment().validateRequiredProperties();检验属性的合法 3)、earlyApplicationListeners = new LinkedHashSet<>();保存容器中早期的事

guigui_xia的博客 398

【Spring源码】 Spring ioc的创建之刷新容器(二)

相关文章 【Spring源码】Spring ioc创建的流程(一) 文章目录相关文章一. 刷新容器的源码1. 准备刷新容器 prepareRefresh();2. 获取beanFactory3. 给 DefaultListableFactoryBean 赋值4. postProcessBeanFactory(beanFactory); 一. 刷新容器的源码 @Override pu...

Not_a_penny_to_name的博客 199

【Spring源码】 Spring ioc的创建之刷新容器(三)

相关文章 【Spring源码】Spring ioc创建的流程(一) 【Spring源码】 Spring ioc的创建之刷新容器(二) 【Spring源码】 Spring ioc的创建之刷新容器(三) 文章目录相关文章一. 刷新容器的源码5.invokeBeanFactoryPostProcessors6. registerBeanPostProcessors 注册bean后置处理器7. init...

Not_a_penny_to_name的博客 239

Spring - 手把手分析 IoC 容器创建过程

Spring - 手把手分析 IoC 容器创建过程

业精于勤荒于嬉 2870

04.Spring Ioc 容器 - 刷新

基本概念Spring Ioc 容器被创建之后,接下来就是它的初始化过程了。该过程在 ConfigurableApplicationContext 的 refresh 方法中定义。该接口的继承关系如下:由于这里 Spring 的配置文件默认采用 xml 形式,所以 Ioc 容器为 XmlWebApplicationContext。接下来就以该类的 refresh 方法为入口,探究下 Ioc 容器的初始

一把空心菜 2044

SPRING10_SPRING的生命周期流程图、容器刷新12大步

SPRING10_SPRING的生命周期流程图、容器刷新12大步

所得皆惊喜 779

spring IOC容器创建过程详解

启动服务,实际上是创建spring IOC容器的过程,而IOC容器的实质是多种Map集合的组合,最终的数据存在多个Map中 public AnnotationConfigApplicationContext(Class<?>… annotatedClasses) { this(); register(annotatedClasses); refresh(); } 从这段代码可以看出,s...

学习达人的日记本 2162
上一篇: LocalDate 与 LocalDataTime
下一篇: IDEA 常用快捷键
cashZhang27
博客等级 码龄10年 22粉丝 67原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值