01Spring的IOC与DI

0、Spring概述

参考文献,官网

0.0、什么是Spring

Spring是一个以IOC(控制反转)和AOP(面向切面编程)为内核的框架。IOC是Spring的基础,简单地说,就是以前调用new构造函数方法来创建对象,现在变成成使用Spring来创建对象。DI(依赖注入)与IOC的含义相同,从两个角度来描述同一个概念。简单的说,DI就是对象的属性,已经被注入好相关的值,直接使用即可。

0.1、Spring概述

Spring是分层的JavaSE/EE应用full-stack轻量级开源框架,以IOC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的JavaEE企业应用开源框架。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MU3SFzc3-1579008477796)(0.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eBrCh6ms-1579008477798)(01.png)]


0.2配置小结

0.2.1、POM.XML配置

	<dependencies>

	<!--提供在IOC基础上扩展的功能-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
        
        
          <!--  解析切入点表达式-->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.7</version>
    </dependency>
        
        		<!--Spring Jdbc-->
 	<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
        
     	<!--Spring事务-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
            
    </dependencies>
        		

0.2.2、配置文件

	<?xml version="1.0" encoding="UTF-8"?>
     <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
        
         <!-- 告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans约束中
            而是一个名称为context名称空间和约束,会扫描所有注解
        -->
        <context:component-scan base-package="com.itheima"></context:component-scan>
        
        		<!--开启aop-->
		<aop:aspectj-autoproxy/>
		
		==============配置Bean===============
<!--<bean id="user" class="com.domain.User"></bean>-->

<!--<bean id="userFactory"  class="com.Factory.Factory">-->

<!--</bean>-->

<!--<bean id="user" factory-bean="userFactory" factory-method="getUser"></bean>-->

<!--<bean id="accountDao" class="com.Dao.AccountDaoImpl">-->

<!--</bean>-->

<!--<bean id="accountService" class="com.Service.AccountServiceImpl" scope="prototype"></bean>-->

<!--<bean id="accountService" class="com.Service.AccountServiceImpl">-->
    <!--<constructor-arg name="name" value="zhoujian"></constructor-arg>-->
    <!--<constructor-arg name="age" value="11"></constructor-arg>-->
    <!--<constructor-arg name="birthday" ref="now"></constructor-arg>-->
    
    
    
<bean id="accountService" class="com.Service.AccountServiceImpl">
   <property name="list" >
       <!-- 注入List数据集合-->
       <list>
           <value>AAA</value>
           <value>BBB</value>
           <value>CCC</value>
       </list>
   </property>

    <!-- 注入String[]数据集合-->
    <property name="str">
        <array>
            <value>1</value>
            <value>2</value>
            <value>3</value>
        </array>
    </property>

    <!-- 注入Set数据集合-->
    <property name="set">
        <set>
            <value>1</value>
            <value>2</value>
        </set>
    </property>

    <property name="map">
        <map>
            <entry key="1" value="2"></entry>
            <entry key="2" value="3"></entry>
        </map>
    </property>
</bean>
<!--</bean>-->
<bean id="now" class="java.util.Date"></bean>
<bean id="dao" class="com.Dao.AccountDaoImpl"></bean>

				 <!--配置账户的持久层-->
	    <bean class="com.itheima.dao.Impl.AccountDaoImpl" id="accountDao">
	        <!--注入数据库操作模板-->
	        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
	    </bean>
	
	    <!--配置JDBCTemplate,数据库操作模板-->
	    <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
	        <!--注入数据源-->
	        <property name="dataSource" ref="ds"></property>
	    </bean>
	
	    <!--配置数据源-->
	    <bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
	        <property name="url" value="jdbc:mysql://localhost:3306/eesy?useUnicode=true&amp;characterEncoding=UTF-8&amp;userSSL=false&amp;serverTimezone=GMT%2B8"></property>
	        <property name="username" value="root"></property>
	        <property name="password" value="123456"></property>
	    </bean>

		 <!--  1、配置Logger类,可以增强的方法-->
<bean id="logger" class="com.itheima.utils.Logger"></bean>
<!--2、配置aop-->
<aop:config>
    <!-- 使用 aop:aspect表明开始配置切面  -->
    <aop:aspect id="logAdvice" ref="logger">

        <!--配置通知的类型并且建立通知方法和切入点方法的关联,实现增强-->
        <aop:before  method="beforeprintLog" pointcut="execution( * com.itheima.service.Impl.*.*(..))"></aop:before>

        <!--配置后置通知和异常通知只能运行一个-->
        <aop:after-returning  method="afterReturingprintLog" pointcut="execution( * com.itheima.service.Impl.*.*(..))"></aop:after-returning>
        
        
              <!--配置异常通知-->
        <aop:after-throwing  method="afterThrowingprintLog" pointcut="execution( * com.itheima.service.Impl.*.*(..))"></aop:after-throwing>
        
        
                <!--配置最终通知-->
        <aop:after  method="afterprintLog" pointcut="execution( * com.itheima.service.Impl.*.*(..))"></aop:after>

        <aop:after  method="afterprintLog" pointcut-ref="pt1"></aop:after>

        <!-- 配置切入点表达式 id属性用于指定表达式唯一标志。expression属性用于指定表达式内容
            此标签写在aop:aspect标签内部只能当前切面使用,
            它还可以写在aop:aspect外面,此时就变成了所有切面可用
        -->
        <aop:pointcut id="pt1" expression="*com.itheima.service.Impl.*.*(..)"></aop:pointcut>

        <!-- 配置环绕通知 详细的注释请看Logger类中-->
        <aop:around method="aroundPrintLog" pointcut="execution( * com.itheima.service.Impl.*.*(..))"></aop:around>
        
        
    </aop:aspect>

</aop:config>
    
 </beans>   
        
        

0.3、Spring的优势

方便解耦,简化开发

通过Spring提供的IOC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类,属性文件解析等这些底层的需求编写代码,可以更加专注于上层的应用。

AOP编程的支持

	> 通过Spring的AOP功能,方便进行面向切面的编程,许多不容易用传统的OOP实现的功能可以通过AOP轻松应付。

声明是事务的支持

>可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明方式灵活的进行事务的管理,提高开发的效率和质量。

方便集成各种优秀的框架

	>Spring可以降低各种框架的使用难度,提供了对各种优秀框架(Structs、Hibernate、Hessian、Quartz等)的直接使用。

1、程序的耦合和解耦

1.1、什么是程序的耦合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E8inlQ2P-1579008477800)(02.png)]




[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RtQD3dWM-1579008477801)(03.png)]

1.2、解决程序耦合的思路

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pkFVc9Ia-1579008477802)(04.png)]

1.3、工厂模式解耦

在实际开发中我们可以吧三层的对象都使用配置文件配置起来,当启动服务器应用加载时,让一个类中的方法通过读取配置文件,吧这些对像创建并存起来,在接下来使用的时候,直接拿过来使用就好了
那么读取配置文件,创建和获取三层对象的类就是工厂
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-io8utQN0-1579008477803)(05.png)]


自己写的工厂类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-akTn6kOq-1579008477804)(06.png)]

1.4、控制反转(IOC)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2fEbbbj9-1579008477805)(07.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KoUN1hKJ-1579008477806)(08.png)]
这种被动接受的方式是获取对象的思想就是控制反转,它是Spring框架的额核心之一

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p5rZbQLd-1579008477807)(09.png)]

1.5、控制反转的另外一种解释

在面向对象传统编程方式中,获取对象的方式通常是用new关键字主动创建一个对象。Spring中的IOC方式对象的生命周期由Spring框架提供的IOC容器来管理,直接从IOC容器中获取一个对象,控制权从应用程序交给了IOC容器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0oSJUScm-1579008477823)(27.png)]
IOC理论上借助于“第三方”实现具有依赖关系对象之间的耦合,即把各个对象类封装之后,通过IOC容器来关联这些对象类.这样对象与对象之间就通过IOC容器进行联系,而对象与对象之间没有直接的联系

应用程序在没有引入IOC容器之前,对象A依赖对象B,那么对象A在实例化或者运行到某一点的时候,自己必须主动创建对象B,其中无论是创建还是使用自己创建的对象B,控制权都在应用程序自身。如果应用程序引入了IOC容器之后,对象A和对象B之间失去了直接联系,那么当对象A实例化和运行时,如果需要对象B,IOC容器就会主动创建一个对象B注入(依赖注入)到对象A所需要的地方。由此,对象A获得依赖对象B的过程,由主动形为变为被动行为,即把创建对象交给了IOC容器处理,控制权颠倒过来了,这就是所谓的控制倒转

2、使用Spring的IOC解决程序耦合的问题

Spring框架的主要功能是通过其核心容器来实现的。Spring框架提供的两种核心容器分别是:BeanFactory和ApplicationContext。

2.1配置的简单使用

2.1.1配置bean.xml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lMhWqnT1-1579008477824)(10.png)]

2.1.2测试配置是否成功

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HU0nYwIr-1579008477825)(11.png)]

2.2Spring基于XML的IOC细节

2.2.1、Spring中工厂类,创建容器的类

在Spring中创建容器,也就是利用工长的方式创建一个Map很重要,对于不同的场景下存在不同创建容器(Container)的工厂类,下面我们做一个梳理。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w3zOCX30-1579008477826)(12.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EEKIMSNI-1579008477826)(13.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XZwNDCIO-1579008477827)(14.png)]

BeanFactory采用了工厂设计模式,即Bean容器模式,负责读取Bean的配置文件,管理对象的生成、加载,维护Bean对象与Bean对象之间的依赖关系,负责Bean的生命周期。对于简单的应用程序来说,使用BeanFactory就已经足够管理Bean了。

2.2.2BeanFactory和ApplicationContext的接口区别

BeanFactory才是Spring容器的中的顶层接口
ApplicationContext是他的子接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EwlJFznM-1579008477828)(15.png)]

2.2.3ApplicationContext接口的实现类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KhYwkZmX-1579008477829)(16.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eazpKcJC-1579008477830)(17.png)]
配置文件包含Bean的id、类、属性及其值,包含一个元素和数个子元素。Spring IOC框架可根据Bean的id从Bean配置文件取得该Bean类,并生成该类的一个实例对象,继而从配置文件中获得该对象的属性和值

2.3、IOC中Bean标签和管理对象的细节

2.3.1Bean标签

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nIUQzH2V-1579008477831)(18.png)]

2.3.2、Bean标签的作用范围

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-srkXN8Tp-1579008477832)(19.png)]

2.3.3Bean标签的生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-03QPRS9h-1579008477833)(20.png)]

2.3.4实例化Bean标签的三种方式

(1)使用默认无参构造函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1l0F5ANd-1579008477834)(21.png)]
(2)Spring管理静态工厂-使用静态工厂的方法创建对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0pLx0NoX-1579008477835)(22.png)]
(3)Spring管理实例工厂-使用实例工厂的方法创建对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PqThmHQb-1579008477836)(23.png)]

3、Spring的依赖注入

3.1、依赖注入的概念

依赖注入:Dependency Injection.它是Spring框架核心ioc的具体表现

我们在编写程序时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。ioc解耦只是降低他们的依赖性,但不会消除。例如:我们的业务层仍会调用持久层的方法

那种业务层和持久层的依赖关系,在使用Spring之后,就让Spring来维护了>

简单来说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取

DI是Dependecy Inject的缩写,译为“依赖注入”。所谓依赖注入,就是由IOC容器在运行期间动态地将某种依赖关系注入对象之中。例如,将对象B注入(注销)给对象A的成员变量。

事实上,依赖注入(DI)和控制反转(IOC)是对同一件事情的描述,从某个方面讲,就是他们描述的角度不同。依赖注入时从应用程序的角度描述,即应用程序依赖容器创建并注入它所需要的外部资源:而控制反转是从容器的角度描述,即容器控制应用程序,由容器反向地向应用程序注入应用程序所需要的外部资源。

如前所述,依赖注入(DI)和控制反转(IOC)是对同一件事情的不同描述。依赖注入的作用是在使用Spring框架创建对象时,动态的将其所依赖的对象注入Bean组件中,其通常实现方式有两种:一种是属性setter()方法注入;另一种是构造方法注入

属性setter()方法注入:IOC容器使用setter()方法注入被依赖的实例。
通过调用无参构造器或无参静态构造方法实例化Bean后,调用Bean的setter()方法,即可实现基于setter()方法的依赖注入。
该方法简答,直观,而且容易理解,所以Spring的设置注入被大量使用。


构造方法注入:IOC容器使用构造方法注入被依赖的实例,基于构造方法的依赖注入通过调用带参数的构造方法来实现,每个参数代表一个依赖。

3.2、构造函数注入

在这里插入图片描述

3.3、set方法注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w0T2vJ7y-1579008477838)(25.png)]

3.4注入集合属性

顾名思义,就是给类中的集合成员传值,它用的是set方法注入的方式,只不过变量的数据类型都是集合。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DBhazICW-1579008477839)(26.png)]

4、Bean的配置总结

4.1、Bean的配置

Spring如同一个工厂,由于生产和管理Spring容器中的Bean。要使用这个工厂,需要开发者对Spring的配置文件进行配置。在实际开发中,最常采用XML格式的配置方式,即通过XML文件夹注册并管理Bean之间的依赖关系。

在Spring中,XML配置文件的跟元素是,中可以包含多个子元素,每一个子元素定义了一个Bean,并描述了该Bean如何被装配到Spring容器中。子元素中包含多个属性

属性或子元素名称说明
idBean的唯一标志符,Spring容器对Bean的配置、管理都通过该属性进行。
nameSpring容器通过此属性进行配置和管理
class指定Bean的实现类,它必须使用类的全限定名
scope用于设定Bean实例的作用域,其属性值有singleton(单例)、prototype(原型)、request、Session、gloable、application和webSocket
property元素的子元素,用于调用Bean实例中的setter()方法完成属性赋值。从而完成依赖注入。钙元素的name属性指定Bean实例中的相应属性名,ref属性或value属性用于指定参数值
constuctor-arg元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的index属性指定构造参数的序号(从0开始),type属性指定构造参数的类型,参数值可以通过ref或value子元素指定
ref、等元素的属性或子元素,可以用于指定对Bean工厂中某个Bean实例的引用
value、等元素的属性或子元素,可以直接用于给定一个常量值
list用于封装List或数组属性的依赖注入
set用于封装Set类型属性的依赖注入
map用于封装Map类型属性的依赖注入
entry元素的子元素,用于设置一个键值对。其key属性指定字符串类型的键值,ref属性或value属性直接指定其值,可以通过ref或value子元素指定其值

4.2Bean的装配方式

Bean的装配方式可以理解为依赖关系注入,Bean的装配方式即Bean依赖注入方式。Spring容器支持多种形式的Bean装配方式,如基于XML的装配、基于Annotation(注解)的装配和自动装配等。


建议在自己的工程中所开发的类尽量使用注解的方式,因为使用它并不困难,甚至可以说更为简单,而对于引用第三方包或者服务的类,尽量使用XML方式,这样的好处是可以尽量对第三方包或者服务的细节减少理解,也更加清晰和明朗。<b推荐使用XML+注解的混合开发**


4.2.1、基于XML的装配/注入依赖

基于XML装配的的头文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JSs4fjHt-1579008477839)(35.png)]

Spring提供了两种基于XML的装配方式:设置注入(Setter Injection)和构造注入(Constructor Injection).

在Spring实例化Bean的过程中,Spring首先会调用Bean的默认构造方法来实例化Bean对象,然后通过反射的方式调用setter()方法来注入属性值。因此,设值注入要求一个Bean必须满足以下两点要求:

  • Bean类必须提供一个默认的无参构造方法。

  • Bean类必须为需要注入的属性提供对应的setter()方法。

使用设置注入时,在Spring配置文件时需要使用元素的子元素来为每个属性注入值;而使用构造注入时,在配置文件中需要使用元素的子元素来定义构造方法的参数,可以使用其value属性来设定值。

4.2.2基于注解的装配/依赖注入

以下的为半自动注解的方式,即必须拥有配置文件bean.xml;为了实现全自动往往需要有一个配置类,详情见4.2.3
基于注解装配的头文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bfGD0XIK-1579008477840)(36.png)]
注意多了个context
为了自动检测匿名的包,需要添加<context:component-scan base-package>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qdwz5SJo-1579008477841)(37.png)]
在装配中,尽管使用XML配置文件可以实现Bean的装配工作,但如果应用中有很多Bean就会导致XML配置文件过于臃肿,给以后的维护和升级工作带来一定的困难。为此,Spring提供了对Annotation技术的全面支持。


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGvWRAUG-1579008477842)(29.png)]

注解名称说明
@Component可以使用此注解描述Spring中的Bean,但它是一个泛华的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需要将该注解标注在响应的类即可。
@Repository用于将数据访问层(DAO层)的类标志位Spring中的Bean,其功能与@Component相同
@Service通常作用在业务层(Service)层,用于将业务层的类标志位Spring中的Bean,其功能与@Component相同
@Controller通常作用在控制层(如Spring MVC的controller),用于将控制层的类标志位Spring中的Bean,其功能与@Component相同
@Autowired用于对Bean的属性变量、属性的setter()方法及构造方法进行标注,配合对应的注解处理器完成Bean的自动装配工作,默认按照Bean的类型进行装配
@Qulifier与@Autowired注解配合使用,会将默认的按Bean类型装配修改为按Bean的实例名装配,Bean的实例名称由@Qualfier注解的参数指定
@Resource其作用于@Autowired一样,区别在于@Autowired默认按照Bean类型装配,而@Resource默认按照Bean的实例名称装配。@Resource中有两个重要属性:name和type。Spring将Name属性解析为Bean的实例名称,type属性解析为Bean的实例类型。若指定name属性,则按照实例名称进行装配;若指定type属性,则按Bean类型进行装配;若都不指定,则先按照Bean实例名称,不能匹配时在按照Bean类型进行装配。

一般情况下,采用自动注入依赖的方式@Autowired。

用于创建对象

用于依赖注入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Pdam5Up-1579008477843)(31.png)]用于改变作用范围**
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rv6I5MaV-1579008477844)(32.png)]

用于改变生命周期
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kRgs6Swd-1579008477845)(33.png)]

总结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lyhvyg2G-1579008477846)(34.png)]

4.2.3基于全自动注解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IiwT5wO1-1579008477847)(38.png)]


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wsgj15rv-1579008477848)(39.png)]


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sGbEmYN0-1579008477849)(40.png)]


在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值