狂神说Spring视频 知识整理

1. Spring

spring内容包含IOC、AOP理解、IOC的各种实现方式、Bean声明周期解析、懒加载、两种事务解析等等

​ IOC:控制反转,把创建对象的过程交给Spring进行管理。IOC创建对象交给容器,通过容器去获取对象, 注解方式创建对象 IOC(通过spring的ioc容器,将对象间的依赖关系交由Spring进⾏控制,方便解耦,简化开发)

​ Aop:面向切面,不能修改源代码进行功能增强

​ Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 Expression Language 表达式语言模块组成,具体介绍如下。

Beans 模块:提供了 BeanFactory,是工厂模式的经典实现,Spring 将管理对象称为 Bean。

Core 核心模块:提供了 Spring 框架的基本组成部分,包括 IoC 和 DI 功能。

Context 上下文模块:建立在核心和 Beans 模块的基础之上,它是访问定义和配置任何对象的媒介。ApplicationContext 接口是上下文模块的焦点。

Expression Language 模块:是运行时查询和操作对象图的强大的表达式语言

1.1 简介

官网:https://spring.io/projects/spring-framework#overview

官方下载地址:https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/

GitHub:https://github.com/spring-projects/spring-framework

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.8</version>
</dependency>
    
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.8</version>
</dependency>
  • Spring 是一个开源免费的框架(容器)
  • Spring是一个轻量级的、非入侵式的框架
  • 控制反转(IOC)、面向切面编程(AOP)
  • 支持事务处理,对框架整合的支持

总结:Spring就是一个轻量级的控制反转(IOC)和面向切面(AOP)编程的框架!

1.2 Spring组成

在这里插入图片描述

1、核心容器(Spring Core)

​ 核心容器提供Spring框架的基础功能。Spring以bean的方式进行java应用的各大组件及关系的组织和管理。Spring使用BeanFactory来产生和管理bean,是工厂模式的实现。BeanFactory使用控制反转(IOC)模式来将应用的配置和依赖性规范与实际的应用程序代码分开。

2、应用上下文(Spring Context)

​ 实现了ApplicationContext接口,Spring的上下文,拓展了核心容器,提供事件处理、国际化等功能。

3、Spring面向切面编程(Spring AOP)

​ 提供切面支持,是个轻量级的容器。Spring管理的任何对象都支持AOP,SpringAOP模块基于Spring的应用程序中的对象提供了事务管理服务,通过使用SpringAOP,就可以将声明性事务管理集成在应用程序中。

4、JDBC和DAO模块(Spring DAO)

​ 提供对JDBC的支持,还提供了DAO的支持,提供事务支持。

​ JDBC、DAO的抽象层,提供了有意义的异常层次结构实现,可用该结构来管理异常处理,和不同数据库提供商抛出的错误信息,异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。

5、对象实体映射(Spring ORM)

​ ORM:Object Relational Mapping,指对象实体映射。Spring插入了若干个ORM框架,提供了ORM对象的关系工具,其中包括Hibernate,JDO和IBatisSQL Map等,所有这些都遵从Spring的通用事务和DAO异常层次结构。

6、Web模块(Spring Web)

​ 拓展了Spring上下文,提供Web应用上下文,对Web开发提供功能上的支持,如请求、表单、异常等。

7、MVC模块(SpringWebMVC)

​ MVC框架是一个全功能的构建Web应用程序的MVC实现,通过策略接口,MVC框架编程高度可配置的,MVC容纳了大量视图技术,其中包括JSP,POI等,模型由JavaBean来构成,存放于m当中,而视图是一个接口,负责实现模型,控制器表示逻辑代码,由c的事情。

2. IOC理论推导

在这里插入图片描述
测试 须在业务层调用DAO层
在这里插入图片描述
如果多了一个dao实现类
在这里插入图片描述
调用该方法只能修改UerServiceImpl
在这里插入图片描述
因为需求的改变,程序需要每次都进行对应的修改

在这里插入图片描述

    /**
     * private UserDao userDao = new UserDaoImpl();
     * 耦合性高
     * 因为用户的需求发生改变,需要修改代码 程序适应不了用户的变化
     *
     * 基类UserDao有多个实现
     * 用户使用不同的方法调用(例如默认方法、mysql方法、Oracle方法调用)
     * 此时userDao指向的派生类需要发生改变, 才能调用对应的方法
    **/


    /**
     * 设计思想:程序不动,让客户端去做一些事情
     */
    private UserDao userDao;

    //利用set进行动态实现值的注入!
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
  • 之前 程序是主动创建对象!控制权在程序员手上!

  • 使用了set注入,程序不再具有主动性,而变成了被动的接受对象

    ​ 这种思想,从本质上解决了问题,程序员不用再去管理对象的创建,系统的耦合性大大降低,可以更加专注的在业务的实现上,这是IOC的原型!

在这里插入图片描述
在这里插入图片描述

2.1 IOC本质

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方。控制反转即获得依赖对象的方式反转了
在这里插入图片描述

​ Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

​ 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到零配置的目的

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转时IoC容器,其实现方法时依赖注入(Dependency Injection, DI)

2.2 Hello程序

  1. Hello实体类

    package com.wlf.pojo;
    
    public class Hello {
        private String str;
    
    //    public Hello(String str) {
    //        this.str = str;
    //    }
    
        public String getStr() {
            return str;
        }
    
        public void setStr(String str) {
            this.str = str;
        }
    
        @Override
        public String toString() {
            return "Hello{" +
                    "str='" + str + '\'' +
                    '}';
        }
    }
    
    
  2. beans.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    
        <bean id="helloa" class="com.wlf.pojo.Hello">
            <!--  利用类中的set方法来进行依赖注入-->
            <property name="str" value="Spring"/>
        </bean>
    </beans>
    
  3. MyTest测试类

    import com.wlf.pojo.Hello;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /*
    
        控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建(new)的,使用Spring后,对象由Spring创建
    
        反转:程序本身不创建对象,而变成被动的接收对象。
    
        依赖注入:利用set方法来进行注入
    
    * */
    public class MyTest {
        public static void main(String[] args) {
            //获取spring的上下文对象!
            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            //对象都在Spring中管理, 使用时可以直接去里面取出来
            Hello hl = (Hello) context.getBean("helloa");
            System.out.println(hl.toString());
    
        }
    }
    
  • Hello对象是谁创建的? 对象由Spring创建
  • Hello对象的属性是怎么设置的? 属性由Spring容器设置

这个过程就叫控制反转:

控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建(new)的,使用Spring后,对象由Spring创建

反转:程序本身不创建对象,而变成被动的接收对象。

依赖注入:利用set方法来进行注入

IoC是一种编程思想,由主动的编程变成被动的接收,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IoC就是:对象由Spring来创建、管理、装配!

IoC 最常见以及最合理的实现方式叫做依赖注入(Dependency Injection,简称 DI)。

2.3 IOC创建对象的方式

User.java 实体类[com.wlf.pojo.User]

public class User {
    private String name;

    public User() {
        System.out.println("使用无参构造方式 初始化User\n");
        this.name = "无参构造:wlf";
    }

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    ....
}

MyTest.java 测试类

public class MyTest {

    public static void main(String[] args) {
        /**
         * 使用ClassPathXmlApplicationContext加载XML配置
         * context 获取Spring的上下文对象
         */
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        /**
         * IoC创建对象
         * 无参构造 user
         * 有参构造	userParam
         */
		//无参构造
        User user = (User) context.getBean("user");
        System.out.println(user.getName());
        //有参构造
        User userParam = (User) context.getBean("userParam");
        System.out.println(userParam.getName());
    }
}
  • 使用无参构造创建对象。默认!

    beans.xml

    	<bean id="user" class="com.wlf.pojo.User"></bean>
    
  • 使用有参构造创造对象

    • 第一种,下标赋值!

          <bean id="userParam" class="com.wlf.pojo.User">
              <!--第一种:下标赋值!-->
              <constructor-arg index="0" value="下标赋值:wlf"></constructor-arg>
          </bean>
      
    • 第二种,类型匹配创建,不建议使用!

          <bean id="userParam" class="com.wlf.pojo.User">
              <!--第二种:类型匹配赋值,不建议使用!-->
              <constructor-arg type="java.lang.String" value="类型匹配:wlf"></constructor-arg>
          </bean>
      
    • 第三种,直接通过参数名来设置

          <bean id="userParam" class="com.wlf.pojo.User">
              <!--第三种:直接通过参数名来设置-->
              <constructor-arg name="name" value="参数名赋值:wlf"></constructor-arg>
          </bean>
      

    总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!

3. Spring配置

3.1 alias 别名

user2是容器中user的别名

<alias name="user"  alias="user2"/>

3.2 beans 配置

    <!--
        id: bean的唯一标识符,相当于对象名
        class: bean对象对应的全限定名(包名+类名)
        name: 别名 可以取多个别名 可以用空格、逗号、分号等分割
    -->
    <bean id="user" class="com.wlf.pojo.User" name="user2,u2"></bean>

3.3 import

一般用于团队开发使用,他可以将多个配置文件,导入合并为一个。

项目中会有多个人开发,bean1.xml bean2.xml…,不同的类需要注册不同的bean中,可以利用import将所有的bean.xml合并为一个总的! 使用的时候直接使用总的配置

applicationContext.xml

<import resource="bean1.xml"/>
<import resource="bean2.xml"/>
.....

4 依赖注入

4.1 Set方式注入【重点】

  • 依赖注入:Set注入!
    • 依赖:bean对象的创建依赖于容器!
    • 注入:bean对象中的所有属性,由容器注入!

【环境搭建】

  1. 复杂类型

    public class Address {
        private String address;
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
    
  2. 真实测试对象

    public class Person {
        private String name;
        private Address address;
        private String[] books;
        private List<String> hobbies;
        private Map<String,String > card;
        private Set<String> games;
        private String child;
        private Properties info;
        //.......set and get methods
    }
    
  3. beans.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--                          set方式注入                                 -->
        <bean id="address" class="com.wlf.pojo.Address">
            <property name="address" value="南昌市"/>
        </bean>
    
        <bean id="person" class="com.wlf.pojo.Person">
            
            <!--第一种,普通值(String name)注入, value-->
            <property name="name" value="wlf"/>
            
            <!--第二种,自定义类(Address address) Bean注入,ref
    			输出格式:address=Address{address='南昌市'}
    		-->
            <property name="address" ref="address"/>
    
            <!--第三种,数组(String[] books)注入
    			输出格式:books=[红楼梦, 三国演义, 西游记]
    		-->
            <property name="books">
                <array>
                    <value>红楼梦</value>
                    <value>三国演义</value>
                    <value>西游记</value>
                </array>
            </property>
            
            <!--第四种,list(List<String> hobbies)注入
    			输出格式:hobbies=[听歌, 看书, 写字]
    		-->
            <property name="hobbies">
                <list>
                    <value>听歌</value>
                    <value>看书</value>
                    <value>写字</value>
                </list>
            </property>
            <!--第五种,map(Map<String,String > card)注入
    			输出格式:card={身份证=123344, 银行卡=2344555}
    		-->
            <property name="card">
                <map>
                    <entry key="身份证" value="123344"> </entry>
                    <entry key="银行卡" value="2344555"> </entry>
                </map>
            </property>
            <!--第六种,集合set(Set<String> games)注入
    			输出格式:games=[LOL, BOB]
    		-->
            <property name="games">
                <set>
                    <value>LOL</value>
                    <value>BOB</value>
                </set>
            </property>
            <!--第七种,null空值注入
    			输出格式:child='null'
    		-->
            <property name="child">
                <null/>
            </property>
            <!--第八种,Properties(Properties info)注入
    			输出格式:info={password=12345, username=root}
    		-->
            <property name="info">
                <props>
                    <prop key="username">root</prop>
                    <prop key="password">12345</prop>
                </props>
            </property>
        </bean>
    
    
    
    </beans>
    
  4. 测试类

public class MyTest {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        System.out.println("\n=========================Set方法注入=======================\n");
        Person person = (Person) context.getBean("person");
        System.out.println(person.toString());
    }
}

4.2 构造器注入

4.3 拓展方式注入

<!--                  p命名空间和c命名空间注入                         -->
<beans
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:c="http://www.springframework.org/schema/c"
       ....
       >
    <!-- p命名空间注入,可以直接注入属性的值:property    -->
    <bean id="user" class="com.wlf.pojo.User"  p:name="wlf"/>
    <!-- c命名空间注入,通过构造器注入:construct-args   -->
    <bean id="user" class="com.wlf.pojo.User"  c:name="wlf"/>
</beans>   

4.4 Bean作用域

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 单例模式(Spring默认机制 id与该bean定义相匹配,则只会返回bean的同一实例)

    在SpringIoC容器中仅存在一个Bean实例,Bean以单例方式存在,默认值

    对象创建时间:在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象

    <bean id="user" class="com.wlf.pojo.User"  p:name="wlf" scope="singleton"/>
    
  2. 原型模式(每次从容器中get的时候,都会产生一个新对象!一个bean定义对应多个对象实例)

    每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行了new XXXBean()

    对象创建时间:在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。

    <bean id="user" class="com.wlf.pojo.User"  p:name="wlf" scope="prototype"/>
    
  3. 其余的request、session、application这些会在web开发中使用到!

# 5. Bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式
  • Spring会在上下文中自动寻找,并自动给bean装配属性!

在Spring中有三种装配的方式

public class Person {
    private Cat cat;
    private Dog dog;
    private String name;
    ....
}

5.1 XML手动配置

  1. 在xml中显示的配置

    <!--方式一:xml显示配置-->
    <bean id="cat" class="com.wlf.pojo.Cat"/>
    <bean id="dog" class="com.wlf.pojo.Dog"/>
    
    <bean id="person" class="com.wlf.pojo.Person">
        <property name="name" value="wlf"/>
        <!--Person类中含基类cat对象 private Cat cat; name是变量名 ref是赋值参数-->
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    </bean>
    
  2. 在java中显示配置

  3. 隐式的自动装配bean【重要】 ByName/ByType自动装配

    <bean id="Cat" class="com.wlf.pojo.Cat"/>
    <bean id="dog" class="com.wlf.pojo.Dog"/>
    
    <!--方式二:隐式自动装配-->
    
    <!-- public void setCat(Cat cat){}
       		byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanID(首字母要小写)!
       		byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean!
    -->
    <bean id="person" class="com.wlf.pojo.Person" autowire="byName">
        <property name="name" value="wlf"/>
    </bean>
    

    小结:

    • ByName 需要保证所有bean的id唯一,并且这个bean需要 和 自动注入的属性set方法的值一致!!
    • ByType 需要保证所有bean的class唯一,并且这个bean需要 和 自动注入的属性类型一致!

5.2 使用注解实现自动装配

要使用注解须知:

  1. 导入约束: context约束

    <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
                    http://www.springframework.org/schema/beans/spring-beans.xsd
                    http://www.springframework.org/schema/context
                    http://www.springframework.org/schema/context/spring-context.xsd">
    
  2. 配置注解的支持: <context:annotation-config/ > 【重要】

    @Autowired 直接在属性上(也可在set方法上)使用即可! 类中也可不添加set方法

    @Resource 根据名字(ByName)或者类型(ByType)来匹配

    @Resource(name=“XXX”)指定唯一的bean

    @Nullable  若字段标记了这个注解,说明这个字段可以为null
    public Person(@Nullable String name) {
        this.name = name;
    }
    
    public @interface Autowired {
        boolean required() default true;
    }
    

    测试

        //xml
        <bean id="cat" class="com.wlf.pojo.Cat"/>
        <bean id="dog" class="com.wlf.pojo.Dog"/>
        <bean id="person" class="com.wlf.pojo.Person"/>
    
public class Person{
    //如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
    @Autowired(required = false)
    private Cat cat;
    /**
    *若@Autowired自动装配的环境比较复杂,可以使用@Qualifier(value="XXX")指定唯一的bean对象
    **/
    @Autowired
    @Qualifier(value="dog")  
    private Dog dog;
    private String name;
}

小结:

@Resource和@Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired 默认通过ByType方式实现 配合@Qualified(value=“XXX”)使用
  • @Resource (name=“XXX”) 默认通过ByName寻找,如果找不到名字就通过ByType

6. 使用注解开发

在Spring4之后,要使用注解开发,必须要保证aop的包导入了

使用注解需要导入context约束,增加注解的支持!

<?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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
		
    <context:annotation-config/>
    <!--指定要扫描的包,这个包下面的注解就会生效-->
    <context:component-scan base-package="com.wlf.pojo"/>
</beans>
  • 注册bean

  • 属性如何注入

    @Component  //等价于new了一个对象 <bean class="com.wlf.pojo.User" id="user"></bean>
    public class User {
    
        //相当于  <property name="name" value="wlf"/>
        @Value("wlf")
        private String name;
        
        //或者注解在set方法上面
        @Value("wlf")
        public void setName(String name) {
            this.name = name;
        }
    }
    
  • 衍生的注解

    @Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层

    • dao【@Repository】

    • service【@Service】

    • controller【@Controller】

      这四个注解功能都是一样的,都代表将某个类注册到Spring容器中,装配bean

    标注在一个类上,作用是将被标注的类注册在Spring容器中,将类的实例化交给Spring管理,完成的是bean的注册

    **@Autowired是标注在类中的成员变量或方法上,完成的是bean的注入。**当一个类Class A中需要一个B类型的变量时,在声明变量时加上这个注解,Spring会在容器中寻找有没有。

  • 自动装配

    @Autowired:自动装配通过类型、名字匹配
        如果Autowired不能唯一自动装配上,则需要通过@Qualifier(value="xxx")
    @Resource:自动装配通过名字和类型匹配
    
  • 作用域

    @Component  //等价于new了一个对象 <bean class="com.wlf.pojo.User" id="user"></bean>
    @Scope("prototype")
    public class User {
        ....
    }
    

    总结:

    • xml更加万能,适用于任何场合!维护简单方便
    • 注解 不是自己类使用不了,维护相对复杂

    xml于注解最佳实践:

    • xml来管理bean

    • 注解只负责完成属性的注入

    • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解支持

      <!--指定要扫描的包,这个包下的注解就会生效-->
      <context:component-scan base-package="com.wlf.pojo"/>
      <!--注解驱动-->
      <context:annotation-config/>
      
      

# 7. 使用Java的方式配置Spring

​ 完全不使用Spring的xml配置,全权交给Java来做。JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能。

package com.wlf.config;

import com.wlf.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/*
* 1 如果开启包扫描,加载配置类以后就可以通过反射拿到配置类中的对象
* 2. @Bean只写在方法上,返回的是一个对象,但一般不获得已经在容器中的对象
* */

@Configuration
@ComponentScan("com.wlf.pojo")
public class wlfConfig {

    /*注册一个bean,就相当于之前写的bean标签
        这个方法的名字,相当于bean标签中的id属性
        这个方法的返回值,相当于bean标签中的class属性
    * */
    @Bean
    public User getUser(){
        return new User();  //就是返回要注入到bean的对象!
    }
}
    @Test
    public void test(){
        ApplicationContext context = new AnnotationConfigApplicationContext(wlfConfig.class);
        User user = (User) context.getBean("getUser");
        System.out.println(user.getName());
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值