看这一篇就够了,全网最全、最强分析Spring是如何创建对象的

如果没有用Spring框架,程序员创建对象的方式有以下5种方式:

  1. 使用new关键字。
  2. 使用Class的newInstance()方法。
  3. 使用Constructor的newInstance()方法。
  4. 使用clone()方法。
  5. 使用反序列化。

虽然这些方式都能实现创建一个对象,但在当今的应用开发中对于频繁使用到的类(比如dao层对象),如果频繁的创建对象,无形中会加剧内存的产生,对系统性能产生影响,而且也是不利于管理的。为了解决上述提到的痛点,Spring就应运而生,并且业界在进行企业级开发的时候,都会把它引入到自己的项目中。我们知道Spring在创建对象的时候,有两种方式,一种是singleton(单例),一种是prototype(原型)。默认是singleton的。那么Spring是如何创建对象的呢?我们下面就来聊聊Spring对象创建流程。

Spring加载bean的功能,在代码中可以这样调用:

UserService userService = (UserService) applicationContext.getBean("userService");

下面是getBean方法的源代码,你可以看一下代码里面的注释。

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		// name有可能是 &xxx 或者 xxx,如果name是&xxx,那么beanName就是xxx
		// name有可能传入进来的是别名,那么beanName就是id
		String beanName = transformedBeanName(name);
		Object beanInstance;

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			// 如果sharedInstance是FactoryBean,那么就调用getObject()返回对象
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				// &&&&xxx---->&xxx
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
					.tag("beanName", name);
			try {
				if (requiredType != null) {
					beanCreation.tag("beanType", requiredType::toString);
				}
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

				// 检查BeanDefinition是不是Abstract的
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					// dependsOn表示当前beanName所依赖的,当前Bean创建之前dependsOn所依赖的Bean必须已经创建好了
					for (String dep : dependsOn) {
						// beanName是不是被dep依赖了,如果是则出现了循环依赖
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// dep被beanName依赖了,存入dependentBeanMap中,dep为key,beanName为value
						registerDependentBean(dep, beanName);

						// 创建所依赖的bean
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
				else {
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
					}
					Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {  // session.getAttriute(beaName)  setAttri
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new ScopeNotActiveException(beanName, scopeName, ex);
					}
				}
			}
			catch (BeansException ex) {
				beanCreation.tag("exception", ex.getClass().toString());
				beanCreation.tag("message", String.valueOf(ex.getMessage()));
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
			finally {
				beanCreation.end();
			}
		}

		// 检查通过name所获得到的beanInstance的类型是否是requiredType
		return adaptBeanInstance(name, beanInstance, requiredType);
	}

这句代码实现了什么样的功能呢?我们可以先看一下这个程序代码的流程图。

d3bc14edde0142178f213cdc8d0ee29a.jpeg

从上面这个流程图可以看出获取bean经历了一个相当复杂的流程,对于获取bean的过程所涉及的步骤大致如下。

  1. 转换对应beanName

方法入参传入的name,不一定是对应的beanName,有可能是别名,也可能是FactoryBean,所以需要进行一系列的解析。主要的处理逻辑是:

  • 去除FactoryBean的修饰符,也就是如果传入的name为&aa,那么会首先去掉“&”字符,返回aa。
  • 如果传入的name是一个alias,要取得最终指向的真实bean。例如别名A指向名称为B的bean,则返回B;若别名A指向别名B,别名B又指向名称为C的bean,则返回C。
  1. 尝试从缓存中获取bean对象

如果使用Spring创建的Bean是单例模式,那么同一个容器只会创建一次。后续在获取相同的bean对象,就直接从单例缓存中获取了。这首先尝试从缓存中获取bean对象,如果获取不到,则再次从singletonFactories中获取。因为创建单例bean的时候,会存在循环依赖的问题,为了避免循环依赖,Spring中创建bean的原则是不等bean创建完成,就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦bean创建时候需要依赖上一个bean,则直接使用ObjectFactory。

这部分的代码在下面,你可以看一下。

public Object getSingleton(String beanName) {
    //true表示允许早期的依赖引用。
		return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//检查缓存中是否存在对象。
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
        //如果为空,则锁定singletonObjects,并进行处理。
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
              //当某些方法需要提前初始化的时候会调用addSingletonFactory方法将对应
              //的ObjectFactory初始化策略存储在singletonFactories中。
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
                //调用预先设定的getObject方法。
								singletonObject = singletonFactory.getObject();
								//记录在缓存中,earlySingletonObjects和singletonFactories互斥。
                this.earlySingletonObjects.put(beanName, singletonObject);
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

这个方法首先尝试从singletonObjects获取对象实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject来创建bean,并放入earlySingletonObjects里面去,并且从singletonFactories里面删除掉这个ObjectFactory。

这个方法里面引用了几个map,下面分别说明一下。

  • singletonObjects:用于保存BeanName和创建bean实例之间的关系。
  • singletonFactories:用于保存BeanName和创建bean的工厂之间的关系。
  • earlySingletonObjects:也是保存BeanName和创建bean实例之间的关系,与singletonObjects的不同之处在于,当一个单例bean被放进到这里面后,那么当其他bean创建时需要这个bean,可以通过getSingleton方法直接获得,解决循环依赖的问题。
  1. bean的实例化

从缓存中获得的是bean的原始状态,则需要对bean进行实例化。而getObjectForBeanInstance就是完成这个工作的。第一步调用这个方法来检测正确性。

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		//如果指定的name是工厂相关例如&xxx
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if (mbd != null) {
				mbd.isFactoryBean = true;
			}
			return beanInstance;
		}

		//单例池中的对象不是FactoryBean,则直接返回
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		else {
			//从factoryBeanObjectCache中直接拿对象
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			//到这里已经明确知道beanInstance一定是FactoryBean类型。
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			//containsBeanDefinition检测beanDefinitionMap是否定义beanName。
			if (mbd == null && containsBeanDefinition(beanName)) {
        //将存储XML配置文件到GernericBeanDefinition转换为RootBeanDefinition,
        //如果指定BeanName是子Bean的话同时会合并父类的相关属性。
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			//synthetic为true,表示这个Bean不是正常的一个Bean,可能只是起到辅助作用的,所以这种Bean就不用去执行PostProcessor了
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

这个方法主要做的事情就是beanInstance的name是&aa这样的,并且不是FactoryBean实例,则直接报错,如果是FactoryBean类型的实例,则直接返回。

对于name不是&开头的名字,判断如果不是FactoryBean类型的实例,则直接返回,如果是FactoryBean类型的实例,则交给getObjectFromFactoryBean方法来创建实例对象。

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		  // 如果是单例模式
      if (factory.isSingleton() && containsSingleton(beanName)) {
			// 多个线程同时来创建就要进行控制,保证单例
			synchronized (getSingletonMutex()) {
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					// 执行getObject()方法,返回的object不可能为null(会返回NullBean)
					object = doGetObjectFromFactoryBean(factory, beanName);
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
						if (shouldPostProcess) {
							if (isSingletonCurrentlyInCreation(beanName)) {
								return object;
							}
							beforeSingletonCreation(beanName);
							try {
								// getObject()方法返回的对象进行后置处理
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
								afterSingletonCreation(beanName);
							}
						}
						if (containsSingleton(beanName)) {
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		else {
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			if (shouldPostProcess) {
				try {
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}

在上面这个方法中判断如果是单例模式,则调用
doGetObjectFromFactoryBean方法创建一次实例对象,之后则是从factoryBeanObjectCache缓存对象中获取,以便于下次复用。接下来判断如果需要后置处理,那么则根据单例创建前、创建单例、单例创建后的顺序,依次执行后置处理逻辑。


doGetObjectFromFactoryBean又把创建对象的责任下派到doGetObjectFromFactoryBean方法。

private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
		Object object;
		try {
			if (System.getSecurityManager() != null) {
				AccessControlContext acc = getAccessControlContext();
				try {
					object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				object = factory.getObject();
			}
		}
		catch (FactoryBeanNotInitializedException ex) {
			throw new BeanCurrentlyInCreationException(beanName, ex.toString());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
		}

		if (object == null) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(
						beanName, "FactoryBean which is currently in creation returned null from getObject");
			}
			object = new NullBean();
		}
		return object;
	}

最终看到Spring使用的是实现FactoryBean接口的实现类的getObject方法来获取对象。

  1. 获取单例

在doGetBean方法中首先使用getSingleton(String beanName)获取beanName对应类型的实例对象。如果没有从缓存中获取到beanName对应类型的实例对象,则执行对象创建逻辑。其中在创建单例的时候,使用重载方法getSingleton(String beanName, ObjectFactory<?> singletonFactory)来获取单例对象。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		// 单例池对象需要同步锁定。
  	synchronized (this.singletonObjects) {
      // 检查单例池中是否已经创建过。
			Object singletonObject = this.singletonObjects.get(beanName);
      // 如果没有创建过,才执行创建逻辑。
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}

				// 添加到单例池
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

这个代码使用到了回调方法,使得可以在单例创建前beforeSingletonCreation(beanName)把当前创建的beanName加入到
singletonsCurrentlyInCreation这个变量中,singletonsCurrentlyInCreation作用就是在于判断是否产生了循环依赖。而真正创建单例对象不是在这个方法中实现的,是在ObjectFactory类型的实例singletonFactory中实现的。addSingleton(beanName, singletonObject)方法把创建的singletonObject放入单例池singletonObjects变量中,以及放入注册单例beanName的集合registeredSingletons中,并且从singletonFactories中删除beanName对应的ObjectFactory,删除earlySingletonObjects变量中beanName对应的对象。addSingleton相关代码如下:

protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, singletonObject);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
}

bean对象的创建是在getSingleton方法中传入的ObjectFactory类型的lamda表达式,重写的getObject方法中的createBean方法实现的。

  1. 准备创建bean

让我们看看createBean方法函数中做了哪些准备工作。

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

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// 马上就要实例化Bean了,确保beanClass被加载了
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

    // 验证及准备覆盖的方法。
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// 实例化前
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

这个方法主要做的工作如下:

  • 把beanName对应的类加载到类加载器中,并且返回Class对象。
  • 对override属性进行标记及验证。

对于方法的匹配来讲,如果一个类中存在若干个重载方法,在函数调用及增强的时候还要根据参数类型进行匹配,来最终确认当前调用的到底是哪个函数。Spring把其中一部分匹配工作在这个方法里完成了。如果当前类中的方法只有1个,那么就设置没有重载方法,这样在后续调用的时候就可以直接使用找到的方法,而不需进行方法的参数匹配验证了,而且还可以对方法的存在性进行验证,可谓是一箭双雕。

  • 实例化的前置处理。

在真正调用doCreateBean方法创建bean的实例前调用了
resolveBeforeInstantiation(beanName, mbdToUse)这个方法,该方法可以在实例化前和初始化后对BeanDefinition中的属性做一些调整,用户可以通过实现Spring中开放的接口,来灵活配置自己的业务逻辑。这个函数中有一个很重要的短路判断。

if (bean != null) {
		return bean;
}

当经过实例化前解析之后返回的bean对象不为空,那么将直接返回,忽略掉后续的doCreateBean的创建逻辑。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// synthetic表示合成,如果某些Bean是合成的,那么则不会经过BeanPostProcessor的处理
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
}

这个方法中最重要的是
applyBeanPostProcessorsBeforeInstantiation和applyBeanPostProcessorsAfterInitialization这两个方法。它们分别对bean实例化前和初始化后进行一些处理。

  1. 循环依赖

Spring将循环依赖分为三种情况进行解决:构造器循环依赖、setter循环依赖、prototype范围的依赖处理。下面分别来分析一下:

  • 构造器循环依赖

通过构造器注入产生的循环依赖是无法解决的,只能抛出
BeanCurrentlyInCreationException。Spring将当前正在创建的每一个bean,如果是单例放在singletonsCurrentlyInCreation变量中,如果是prototype放在prototypesCurrentlyInCreation中。程序判断如果这些变量里有记录,则认为依赖的实例还没有创建好。bean创建好之后,则会从这些变量中删除对应的记录。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值