真肝,整理了一周的Spring面试大全【含答案】,吊打Java面试官

81 篇文章 139 订阅
10 篇文章 13 订阅

对于Java的小伙伴来说,Spring是面试的必问环节,我研究Spring多年,甚至我的网名都叫SpringMeng。

最新整理的数据结构和算法的值得收藏:

❤️肝完了,一天掌握数据结构和算法面试题,吊打面试官,建议收藏❤️

小孟肝了一周,继续给大家整理Spring的系列,帮你offer收到手疼。先看下Spring的家族图:

废话不多话,直接上干货。

目录

Q1 什 么 是 spring?

Q2:使 用 Spring 框 架 的 好 处 是 什 么 ?

Q3:使 用 Spring 缺点是什么?

Q4:IoC 是什么?

Q5:IOC的优点是什么

Q6:IoC 容器初始化过程?

Q7:依赖注⼊的实现方法有哪些?

Q8:依赖注⼊的相关注解?

Q9:依赖注入的过程?

Q10:Bean 的生命周期?

Q11:Bean 的作⽤范围?

Q12:如何通过 XML ⽅式创建 Bean?

Q13:Spring 有几种配置方式?

Q14:如何用基于 XML 配置的方式配置 Spring?

Q15:如何通过注解创建 Bean?

Q17:如何通过注解配置⽂件?

Q18:BeanFactory、FactoryBean 和ApplicationContext 的区别?

Q19. 解 释 Spring 框 架 中 bean 的 生 命 周 期 。

Q20、怎样开启注解装配 ?

Q21:Spring 支 持 的 ORM有那些?,

Q22、Spring 框架中的单例 Beans 是线程安全的么?

Q23:Spring 框架中都用到了哪些设计模式?

Q24、请举例解释@Autowired 注解?


Q1 什 么 是 spring?

Spring是个java企业级应用的开源开发框架 。Spring主要用来开发 Java应用,但是有些扩展是针 对构建J2EE 平台的web应用 。Spring 框 架目标是简化Java企业级应用开发,并通过 POJO为基 础的编程模型促进良好的编程习惯 。

Q2:使 用 Spring 框 架 的 好 处 是 什 么 ?

• 轻量 :Spring 是轻量的,基本的版本大约2MB。

• 控制反转 :Spring 通过控制反转实现了松散耦合 ,对象们给出它们的依 赖 ,而不是创建或查找依赖的对象们 。面向切面的编程(AOP):Spring 支持面向切面的编程 ,并且把应用业务逻辑和系统服务分开。容器 :Spring 包含并管理应用中对象的生命周期和配置 。

Dependency Injection(DI) 方法使得构造器和 JavaBean properties 文件中的依赖关系一目了然。

与 EJB 容器相比较,IoC 容器更加趋向于轻量级。这样一来IoC 容器在有限的内存和 CPU 资源的情况下进行应用程序的开发和发布就变得十分有利。

Spring的高度可开放性,并不强制依赖于Spring,开发者可以自由选择Spring部分或全部。

• MVC框架:Spring 的 WEB 框 架 是个精心设计的框架,是 Web 框架的一个很好的替代品。

• 事务管理 :Spring 提供一个持 续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA) 。

• 异常处理 :Spring 提供方便的 API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的) 转化为一致的unchecked异常。

Q3:使 用 Spring 缺点是什么?

1,缺少一个公用控制器;

2,没有SpringBoot好用;

3,Spring像一个胶水,将框架黏在一起,后面拆分的话就不容易拆分了。

总结下Spring的优点和缺点。

Q4:IoC 是什么?

IoC即控制反转,简单来说就是把原来代码⾥需要实现的对象创建、依赖反转给容器来帮忙实现,需要创建⼀个容器并且需要⼀种描述让容器知道要创建的对象间的关系,在 Spring 中管理对象及其依赖关系是通过 Spring 的 IoC 容器实现的。

IoC 的实现方式有依赖注⼊和依赖查找,由于依赖查找使⽤的很少,因此 IoC 也叫做依赖注⼊。

依赖注入具体怎么实现的呢?

依赖注⼊指对象被动地接受依赖类⽽不用自己主动去找,对象不是从容器中查找它依赖的类,而是在容器实例化对象时主动将它依赖的类注入给它。假设⼀个 Car 类需要⼀个 Engine 的对象,那么⼀般需要手动 new一个 Engine,利用 IoC 就只需要定义⼀个私有的 Engine 类型的成员变量,容器会在运行时自动创建⼀个 Engine 的实例对象并将引用自动注⼊给成员变量。

Q5:IOC的优点是什么

IOC 或依赖注入把应用的代码量 降到最低。 它使应 容易测试 ,单元测试不再 需 要 单 例 和 JNDI查找机制。最小的代价和最小的侵入性使松散耦合得以实现 。IOC容器支持加 载 服务时的饿汉式初始化和懒加载 。

Q6:IoC 容器初始化过程?

基于 XML 的容器初始化,当创建⼀个 ClassPathXmlApplicationContext 时,构造方法做了两件事:

① 调用父容器的构造方法为容器设置好 Bean 资源加载器。

② 调用父类的路径。方法设置 Bean 配置信息定位。

ClassPathXmlApplicationContext 通过调用父类 AbstractApplicationContext 的方法启动

整个 IoC 容器对 Bean 定义的载入过程, refresh 是⼀个模板方法,规定了 IoC 容器的启动流程。在创建 IoC 容器前如果已有容器存在,需要把已有的容器销毁,保证在的 IoC 容器。

方法后使用的是新创建容器创建后通过方法加载 Bean 配置资源,该方法做两件事:

① 调用资源加载器的方法获取要加载的资源。

② 真正执行加载功能,由子类 XmlBeanDefinitionReader 实现。加载资源时⾸先解析配置文件路径,读取配置文件的内容,然后通过 XML 解析器将 Bean 配置信息转换成⽂档对象,之后按照 Spring Bean 的定义规则对⽂档对象进⾏解析。

Spring IoC 容器中注册解析的 Bean 信息存放在⼀个 HashMap 集合中,key 是字符串,值是BeanDefinition,注册过程中需要使⽤ synchronized 保证线程安全。当配置信息中配置的 Bean 被解析且被注册到 IoC 容器中后,初始化就算真正完成了,Bean 定义信息已经可以使⽤且可被检索。Spring IoC 容器的作用就是对这些注册的 Bean 定义信息进⾏处理和维护,注册的 Bean 定义信息是控制反转和依赖注⼊的基础。

基于注解的容器初始化分为两种:① 直接将注解 Bean 注册到容器中,可以在初始化容器时注册,也可以在容器创建之后⼿动注册,然后刷新容器使其对注册的注解 Bean 进行处理。② 通过扫描指定的包及其子包的所有类处理, 在初始化注解容器时指定要⾃动扫描的路径。

Q7:依赖注⼊的实现方法有哪些?

构造方法注入: IoC Service Provider 会检查被注⼊对象的构造⽅法,取得它所需要的依赖对象列表,进⽽为其注⼊相应的对象。这种方法的优点是在对象构造完成后就处于就绪状态,可以马上使用。缺点是当依赖对象较多时,构造⽅法的参数列表会比较长,构造方法无法被继承,无法设置默认值。对于非必需的依赖处理可能需要引⼊多个构造方法,参数数量的变动可能会造成维护的困难。

setter 方法注入:当前对象只需要为其依赖对象对应的属性添加 setter 方法,就可以通过 setter 方法将依赖对象注入到被依赖对象中。setter方法注⼊在描述性上要比构造方法注⼊强,并且可以被集成, 允许设置默认值。缺点是无法在对象构造完成后马上进⼊就绪状态。

接口注入:必须实现某个接口,接口提供方法来为其注⼊依赖对象。使用少,因为它强制要求被注入对象实现不必要接口,侵入性强。

Q8:依赖注入的相关注解?

@Autowired :自动按类型注⼊,如果有多个匹配则按照指定 Bean 的 id 查找,查找不到会报错。

@Qualifier :在自动按照类型注入的基础上再按照 Bean 的 id 注入,给变量注入时必须搭配。

@Autowired ,给方法注⼊时可单独使⽤。直接按照 Bean 的 id 注入,只能注入Bean 类型。

Q9:依赖注入的过程?

方法获取 Bean 实例,该方法调⽤Bean 的功能,也是触发依赖注入的地方。具体创建 Bean 对象的过程由 ObjectFactory 的, doGetBean 真正实现从 IoC 容器获取完成,该方法主要通过依赖注入进⾏处理。方法生成Bean 包含的 Java 对象实例和方法对 Bean 属性的。

在 populateBean 方法中,注入过程主要分为两种情况:① 属性值类型不需要强制转换时,不需要解析属性值,直接进行依赖注入。②属性值类型需要强制转换时,首先解析属性值,然后对解析后的属性值进行依赖注⼊。依赖注入的过程就是将 Bean 对象实例设置到它所依赖的 Bean 对象属性上,真正的

依赖注入是通过方法实现的,该方法使用了委派模式。

BeanWrapperImpl 类负责对完成初始化的 Bean 对象进行依赖注入,对于非集合类型属性,使用 JDK反射,通过属性的 setter 方法为属性设置注入后的值。对于集合类型的属性,将属性值解析为⽬标类型的集合后直接赋值给属性。

当容器对 Bean 的定位、载入、解析和依赖注⼊全部完成后就不再需要手动创建对象,IoC 容器会⾃动为我们创建对象并且注入依赖。

Q10:Bean 的生命周期?

在 IoC 容器的初始化过程中会对 Bean 定义完成资源定位,加载读取配置并解析,最后将解析的 Bean 信息放在⼀个 HashMap 集合中。当 IoC 容器初始化完成后,会进行对 Bean 实例的创建和依赖注⼊过程,注⼊对象依赖的各种属性值,在初始化时可以指定自定义的初始化方法。经过这⼀系列初始化操作后 Bean 达到可⽤状态,接下来就可以使⽤ Bean 了,当使用完成后会调⽤ destroy 方法进⾏销毁,此时也可以指定⾃定义的销毁方法,最终 Bean 被销毁且从容器中移除。

XML 方式通过配置 bean 标签中的 init-Method 和 destory-Method 指定自定义初始化和销毁方法。注解方式通过和注解指定⾃定义初始化和销毁方法。

 @PostConstruct 和@PreDestroy 注解方式,使用 customInit()和customDestroy()方法管理 bean 生命周期的代码样例如下:

1. <beans>

2. <bean id="demoBean"

class="com.springmeng.task.DemoBean"

3. init-method="customInit" destroymethod="customDestroy"></bean>

4. </beans>

更多内容请参考:Spring 生命周期 Spring Bean Life Cycle:

https://howtodoinjava.com/spring-core/spring-beanlife-cycle/

Q11:Bean 的作⽤范围?

通过 scope 属性指定 bean 的作用范围,包括:

① singleton:单例模式,是默认作用域,不管收到多少 Bean 请求每个容器中只有⼀个唯⼀的 Bean 实例。

② prototype:原型模式,和 singleton 相反,每次 Bean 请求都会创建⼀个新的实例。

③ request:每次 HTTP 请求都会创建⼀个新的 Bean 并把它放到 request 域中,在请求完成后 Bean会失效并被垃圾收集器回收。

④ session:和 request 类似,确保每个 session 中有⼀个 Bean 实例,session 过期后bean会随之失效。

⑤ global session:当应⽤部署在 Portlet 容器时,如果想让所有 Portlet 共⽤全局存储变量,那么该变量需要存储在 global session 中。

Q12:如何通过 XML ⽅式创建 Bean?

默认无参构造方法,只需要指明 bean 标签中的 id 和 class 属性,如果没有无参构造方法报错。

静态工厂方法,通过 bean 标签中的 class 属性指明静态工厂,factory-method 属性指明静态工厂方法。

实例工厂方法,通过 bean 标签中的 factory-bean 属性指明实例工厂,factory-method 属性指明实例工厂方法。

Q13、Spring 有几种配置方式?

将 Spring 配置到应用开发中有以下三种方式:

1. 基于 XML 的配置

2. 基于注解的配置

3. 基于 Java 的配置

Q14如何用基于 XML 配置的方式配置 Spring?

在 Spring 框架中,依赖和服务需要在专门的配置文件来实现,我常用的 XML 格式的配置文件。这些配置文件的格式通常用开头,然后一系列的 bean 定义和专门的应用配置选项组成。

SpringXML 配置的主要目的时候是使所有的 Spring 组件都可以用 xml 文件的形式来进行配置。这意味着不会出现其他的Spring 配置类型(比如声明的方式或基于 Java Class 的配置方式)。Spring 的 XML 配置方式是使用被 Spring 命名空间的所支持的一系列的 XML 标签来实现的。Spring 有以下主要的命名空间:context、beans、jdbc、tx、aop、mvc 和 aso。

1. <beans>

2.

3. <!-- JSON Support -->

4. <bean name="viewResolver"

class="org.springframework.web.servlet.view.BeanNameVi

ewResolver"/>

5. <bean name="jsonTemplate"

class="org.springframework.web.servlet.view.json.Mappi

ngJackson2JsonView"/>

6.

7. <bean id="restTemplate"

class="org.springframework.web.client.RestTemplate"/>

8.

9. </beans>

Q15:如何通过注解创建 Bean?

把当前类对象存入 Spring 容器中,相当于在 xml 中配置⼀个 bean 标签。value 属性指定 bean 的 id,默认使用当前类的字母首小写的类名。

@Controller,@Service ,@Repository 三个注解都是的衍生注解,作用及属性都是⼀模⼀样的。只是提供了更加明确语义, @Controller 用于控制层,@Service用于业务层,@Repository 用于持久层。如果注解中有且只有⼀个 value 属性要赋值时可以省略 value。

如果想将第三方的类变成组件又没有源代码,也就没办法使用 进行自动配置,这种时候就要使⽤注解。被注解的⽅法返回值是⼀个对象,将会实例化,配置和初始化⼀个新对象并返回,这个对象由 Spring 的 IoC 容器管理。name 属性用于给当前注解方法创建的对象指定⼀个名称,即 bean 的 id。当使用注解配置方法时,如果方法有参数,Spring 会去容器查找是否有可⽤ bean对象,查找方式和⼀样。

1. <web-app>

2. <display-name>Archetype Created Web

Application</display-name>

3.

4. <servlet>

5. <servlet-name>spring</servlet-name>

6. <servlet-class>

7.

org.springframework.web.servlet.DispatcherServlet

8. </servlet-class>

9. <load-on-startup>1</load-on-startup>

10. </servlet>

11.

12. <servlet-mapping>

13. <servlet-name>spring</servlet-name>

14. <url-pattern>/</url-pattern>

15. </servlet-mapping>

16.

17. </web-app>

看到这里的小伙伴,给个三连支持下,祝你offer收到手疼,嘿嘿……一起进步!

Q17:如何通过注解配置⽂件?

⽤于指定当前类是⼀个 spring 配置类,当创建容器时会从该类上加载注解,value 属性用于指定配置类的字节码。

⽤于指定 Spring 在初始化容器时要扫描的包。basePackages 属性用于指定要扫描的包。

用于加载文件中的配置。value 属性用于指定⽂件位置,如果是在类路径下需要加上 classpath。用于导⼊其他配置类,在引入其他配置类时可以不⽤再写注解。有的是父配置类,引入的是子配置类。value 属性用于指定其他配置类的字节码。

Q18:BeanFactory、FactoryBean 和ApplicationContext 的区别?

BeanFactory 是⼀个 Bean 工厂,使用简单工厂模式,是 Spring IoC 容器顶级接口,可以理解为含有Bean 集合的工厂类,作用是管理 Bean,包括实例化、定位、配置对象及建⽴这些对象间的依赖。BeanFactory 实例化后并不会自动实例化 Bean,只有当 Bean 被使⽤时才实例化与装配依赖关系,属于延迟加载,适合多例模式。

FactoryBean 是⼀个工厂Bean,使用了工厂方法模式,作⽤是⽣产其他 Bean 实例,可以通过实现该接⼝,提供⼀个工厂方法来⾃定义实例化 Bean 的逻辑。FactoryBean 接口由 BeanFactory 中配置的对象实现,这些对象本身就是用于创建对象的工厂,如果⼀个 Bean 实现了这个接口,那么它就是创建对象的工厂 Bean,而不是 Bean 实例本身。

ApplicationConext 是 BeanFactory 的子接口,扩展了 BeanFactory 的功能,提供了支持国际化的⽂本消息,统⼀的资源⽂件读取方式,事件传播以及应⽤层的特别配置等。容器会在初始化时对配置的Bean 进行预实例化,Bean 的依赖注入在容器初始化时就已经完成,属于立即加载,适合单例模式,⼀般推荐使用。

Q19. 解 释 Spring 框 架 中 bean 的 生 命 周 期 。

• Spring容器从XML文件中 取 bean的定义,并实例化 bean。

• Spring 根 据 bean 的定义填充所有的属 性 。

• 如果bean实现了BeanNameAware 接口 ,Spring 传递bean 的 ID到setBeanName 方法 。

• 如果 Bean实现了BeanFactoryAware 接口 ,Spring传 递 beanfactory 给 setBeanFactory方法。

• 如果有任何与bean 相关的BeanPostProcessors,Spring会在 postProcesserBeforeInitialization()方 法内 调 用 它 们 。

• 如 果 bean 实 现 IntializingBean了 ,调 用 它 的afterPropertySet 方法 ,如果 bean声明了初始化方法 ,调用此初始化方法 。

•如果有BeanPostProcessors 和bean关联 ,这些 bean的postProcessAfterInitialization() 方法将 被调用 。

• 如果bean实现了DisposableBean, 它将调用destroy()方 法 。

Q20、怎样开启注解装配 ?

注解装配在默认情 况下是不开启的 ,为了使用注解装配 ,我们必须在Spring 配置文件中配置元素 。

Q21:Spring 支 持 的 ORM有那些?,

Spring支持以下ORM:

        1,Hibernate

        2,iBatis

        3,JPA (Java Persistence API)

        4,TopLink

        5,JDO (Java Data Objects)

        6,OJB

Q22、Spring 框架中的单例 Beans 是线程安全的么?

Spring 框架并没有对单例 bean 进行任何多线程的封装处理。

关于单例 bean 的线程安全和并发问题需要开发者自行去搞定。但实际上大部分的 Spring bean 并没有可变的状态(比如 Serview 类和 DAO 类),所以在某种程度上说 Spring 的单例 bean 是线程安全的。如果你的 bean 有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。

最浅显的解决办法就是将多态 bean 的作用域由“singleton”变更为“prototype”。

Q23:Spring 框架中都用到了哪些设计模式?

Spring 框架中使用到了大量的设计模式,下面列举了比较有代表性的:

1. 代理模式—在 AOP 和 remoting 中被用的比较多。

2. 单例模式—在 spring 配置文件中定义的 bean 默认为单例模式。

3. 模板方法—用来解决代码重复的问题。比如. RestTemplate,JmsTemplate, JpaTemplate。

4. 前端控制器—Spring 提供了 DispatcherServlet 来对请求进行分发。

5. 视图帮助(View Helper )—Spring 提供了一系列的 JSP 标签,高效宏来辅助将分散的代码整合在视图里。

6. 依赖注入—贯穿于 BeanFactory / ApplicationContext 接口的核心理念。

7. 工厂模式—BeanFactory 用来创建对象的实。

Q24、请举例解释@Autowired 注解?

@Autowired 注解对自动装配何时何处被实现提供了更多细粒度的控制。@Autowired 注解可以像@Required 注解、构造器一样被用于在 bean 的设值方法上自动装配 bean 的属性,一个参数或者带有任意名称或带有多个参数的方法

比如,可以在设值方法上使用@Autowired 注解来替代配置文件中的元素。当 Spring 容器在 setter 方法上找到@Autowired 注解时,会尝试用 byType 自动装配。

当然我们也可以在构造方法上使用@Autowired 注解。带有@Autowired 注解的构造方法意味着在创建一个 bean 时将会被自动装配,即便在配置文件中使用元素。

1. public class TextEditor {

2. private SpellChecker spellChecker;

3.

4. @Autowired

5. public TextEditor(SpellChecker spellChecker){

6. System.out.println("Inside TextEditor

constructor." );

7. this.spellChecker = spellChecker;

8. }

9.

10. public void spellCheck(){

11. spellChecker.checkSpelling();

12. }

13. }

下面是没有构造参数的配置方式:

1. <beans>

2.

3. <context:annotation-config/>

4.

5. <!-- Definition for textEditor bean without

constructor-arg -->

6. <bean id="textEditor"

class="com.springmeng.TextEditor">

7. </bean>

8.

9. <!-- Definition for spellChecker bean -->

10. <bean id="spellChecker"

class="com.howtodoinjava.SpellChecker">

11. </bean>

12.

13. </beans>

好了,spring面试整理结束,小伙伴们点赞、收藏、评论,一键三连走起呀,下期见~~

最后,我将面试前用到的资料,都分享下,点击下面的,然后关注弹出的图,

回复:csdn面试大全

即可获取所有面试资料

  • 244
    点赞
  • 1379
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 104
    评论
好的,我们开始一场Spring框架领域的面试。 问题1:请问Spring框架是什么?它的核心特性是什么? 回答:Spring框架是一个开源的、轻量级的、基于Java的应用程序开发框架,它提供了一系列的功能和特性,帮助我们更加简化和优化Java应用程序的开发。Spring框架的核心特性包括但不限于:IoC容器、AOP、数据访问、Web开发、测试支持等。下面简单介绍一下Spring框架的核心特性: - IoC容器:Spring框架的IoC容器是其最核心的特性之一,它可以帮助我们管理和组织Java对象的创建、依赖和生命周期。通过IoC容器,我们可以将Java对象之间的依赖关系通过配置文件或注解的方式进行管理,从而实现松耦合、可维护和可扩展的应用程序。 - AOP:Spring框架的AOP(面向切面编程)模块可以帮助我们将程序的横切关注点(如日志、事务等)从业务逻辑中分离出来,实现了代码的重用和模块化开发。 - 数据访问:Spring框架提供了一系列的数据访问技术和工具,包括JDBC、ORM、事务等,可以帮助我们更加方便地访问和操作数据库。 - Web开发:Spring框架提供了一系列的Web开发技术和工具,包括Web MVC、RESTful、WebSocket等,可以帮助我们更加方便地开发Web应用程序。 - 测试支持:Spring框架提供了一系列的测试技术和工具,包括JUnit、Mockito等,可以帮助我们更加方便地进行单元测试、集成测试等。 问题2:请问Spring框架中的IoC容器是什么?它的作用是什么?请举例说明。 回答:Spring框架中的IoC容器是指一种管理和组织Java对象的容器,它可以帮助我们实现对象之间的依赖注入、配置和生命周期管理。Spring框架中的IoC容器有两种实现方式:BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口,提供了更加丰富的功能和特性。下面是一个简单的IoC容器示例: ```java public interface UserService { void addUser(User user); } public class UserServiceImpl implements UserService { public void addUser(User user) { // do something } } public class UserController { private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } public void createUser(User user) { userService.addUser(user); } } // 配置IoC容器 <bean id="userService" class="com.example.UserServiceImp"/> <bean id="userController" class="com.example.UserController"> <property name="userService" ref="userService"/> </bean> // 使用IoC容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserController userController = context.getBean("userController", UserController.class); userController.createUser(new User("Tom", 18)); ``` 这段代码中,我们通过配置文件来定义了一个IoC容器,其中定义了一个名为userService的Java对象和一个名为userController的Java对象,通过属性注入的方式将userService注入到userController中。在程序运行时,我们可以通过IoC容器来获取userController对象,并调用其createUser方法来创建一个新的用户。通过IoC容器,我们实现了Java对象之间的松耦合和可维护性,从而提高了应用程序的可靠性和可扩展性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员springmeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值