Spring面试题集锦(精选)

如下来自网络收集,找不到原文出处。这次主要为了面试收集,但愿对你们有所帮助~~~~java

Spring面试题集锦(精选)

1.什么是Spring?

Spring是一个开源的Java EE开发框架。Spring框架的核心功能能够应用在任何Java应用程序中,但对Java EE平台上的Web应用程序有更好的扩展性。Spring框架的目标是使得Java EE应用程序的开发更加简捷,经过使用POJO为基础的编程模型促进良好的编程风格。git

2.Spring有哪些优势?

  • 轻量级:Spring在大小和透明性方面绝对属于轻量级的,基础版本的Spring框架大约只有2MB。
  • 控制反转(IOC):Spring使用控制反转技术实现了松耦合。依赖被注入到对象,而不是建立或寻找依赖对象。
  • 面向切面编程(AOP): Spring支持面向切面编程,同时把应用的业务逻辑与系统的服务分离开来。
  • 容器:Spring包含并管理应用程序对象的配置及生命周期。
  • MVC框架:Spring的web框架是一个设计优良的web MVC框架,很好的取代了一些web框架。
  • 事务管理:Spring对下至本地业务上至全局业务(JAT)提供了统一的事务管理接口。
  • 异常处理:Spring提供一个方便的API将特定技术的异常(由JDBC, Hibernate, 或JDO抛出)转化为一致的、Unchecked异常。

3. Spring 事务实现方式有哪些?

  • 编程式事务管理:这意味着你能够经过编程的方式管理事务,这种方式带来了很大的灵活性,但很难维护。
  • 声明式事务管理:这种方式意味着你能够将事务管理和业务代码分离。你只须要经过注解或者XML配置管理事务。

4.Spring框架的事务管理有哪些优势?

  • 它为不一样的事务API(如JTA, JDBC, Hibernate, JPA, 和JDO)提供了统一的编程模型。
  • 它为编程式事务管理提供了一个简单的API而非一系列复杂的事务API(如JTA). 它支持声明式事务管理。
  • 它能够和Spring 的多种数据访问技术很好的融合。

5.spring事务定义的传播规则

  • PROPAGATION_REQUIRED: 支持当前事务,若是当前没有事务,就新建一个事务。这是最多见的选择。
  • PROPAGATION_SUPPORTS: 支持当前事务,若是当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY: 支持当前事务,若是当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW: 新建事务,若是当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED: 以非事务方式执行操做,若是当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER: 以非事务方式执行,若是当前存在事务,则抛出异常。
  • PROPAGATION_NESTED:若是当前存在事务,则在嵌套事务内执行。若是当前没有事务,则进行与PROPAGATION_REQUIRED相似的操做。

6.Spring 事务底层原理

  • 划分处理单元——IoC

因为spring解决的问题是对单个数据库进行局部事务处理的,具体的实现首先用spring中的IoC划分了事务处理单元。而且将对事务的各类配置放到了ioc容器中(设置事务管理器,设置事务的传播特性及隔离机制)。github

  • AOP拦截须要进行事务处理的类

Spring事务处理模块是经过AOP功能来实现声明式事务处理的,具体操做(好比事务实行的配置和读取,事务对象的抽象),用TransactionProxyFactoryBean接口来使用AOP功能,生成proxy代理对象,经过TransactionInterceptor完成对代理方法的拦截,将事务处理的功能编织到拦截的方法中。读取ioc容器事务配置属性,转化为spring事务处理须要的内部数据结构(TransactionAttributeSourceAdvisor),转化为TransactionAttribute表示的数据对象。web

  • 对事务处理实现(事务的生成、提交、回滚、挂起)

spring委托给具体的事务处理器实现。实现了一个抽象和适配。适配的具体事务处理器:DataSource数据源支持、hibernate数据源事务处理支持、JDO数据源事务处理支持,JPA、JTA数据源事务处理支持。这些支持都是经过设计PlatformTransactionManager、AbstractPlatforTransaction一系列事务处理的支持。 为经常使用数据源支持提供了一系列的TransactionManager。面试

  • 结合

PlatformTransactionManager实现了TransactionInterception接口,让其与TransactionProxyFactoryBean结合起来,造成一个Spring声明式事务处理的设计体系。算法

7. Spring的单例实现原理

Spring框架对单例的支持是采用单例注册表的方式进行实现的,而这个注册表的缓存是HashMap对象,若是配置文件中的配置信息不要求使用单例,Spring会采用新建实例的方式返回对象实例。spring

8. 有哪些不一样类型的IOC(依赖注入)?

  • 构造器依赖注入:构造器依赖注入在容器触发构造器的时候完成,该构造器有一系列的参数,每一个参数表明注入的对象。
  • Setter方法依赖注入:首先容器会触发一个无参构造函数或无参静态工厂方法实例化对象,以后容器调用bean中的setter方法完成Setter方法依赖注入。
  • 注解注入:基于@Autowired的自动装配,默认是根据类型注入,能够用于构造器、字段、方法注入。

9. 你推荐哪一种依赖注入?构造器依赖注入仍是Setter方法依赖注入?

你能够同时使用两种方式的依赖注入,最好的选择是使用构造器参数实现强制依赖注入,使用setter方法实现可选的依赖关系。数据库

10.简述一下Spring框架?

概念apache

  • Spring致力于Java EE应用的各类解决方案,是一款轻量级框架,大大简化了Java企业级开发,提供了强大、稳定的功能。
  • Spring主要有两个目标:一是让先有技术更易于使用,二是促进良好的编程习惯(或者称为最佳实践)

优势编程

  • 轻量级:Spring在大小和透明性方面绝对属于轻量级的,基础版本的Spring框架大约只有2MB
  • 控制反转(IOC):Spring使用控制反转技术实现了松耦合。依赖被注入到对象,而不是建立或寻找依赖对象。
  • 方便解耦,简化开发:Spring就是一个大工厂,能够将全部对象建立和依赖关系维护,交给Spring管理
  • AOP编程的支持:Spring提供面向切面编程,能够方便的实现对程序进行权限拦截、运行监控等功能
  • 声明式事务的支持:只须要经过配置就能够完成对事务的管理,而无需手动编程
  • 方便集成各类优秀框架:Spring不排斥各类优秀的开源框架,其内部提供了对各类优秀框架(如:Struts二、Hibernate、MyBatis、Quartz等)的直接支持
  • 下降JavaEE API的使用难度:Spring 对JavaEE开发中很是难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大下降

11.简单介绍一下Spring七大模块?

  • Spring Core:Core封装包是框架的最基础部分,提供IOC和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的须要,并真正地容许你从程序逻辑中分离出依赖关系和配置。
  • Spring Context:构建于Core封装包基础上的 Context封装包,提供了一种框架式的对象访问方法,有些象JNDI注册器。Context封装包的特性得自于Beans封装包,并添加了对国际化(I18N)的支持(例如资源绑定),事件传播,资源装载的方式和Context的透明建立,好比说经过Servlet容器。
  • Spring DAO:DAO (Data Access Object)提供了JDBC的抽象层,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码。 而且,JDBC封装包还提供了一种比编程性更好的声明性事务管理方法,不只仅是实现了特定接口,并且对全部的POJOs(plain old Java objects)都适用。
  • Spring ORM:ORM 封装包提供了经常使用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封装包,能够混合使用全部Spring提供的特性进行“对象/关系”映射,如前边提到的简单声明性事务管理。
  • Spring AOP:Spring的 AOP 封装包提供了符合AOP Alliance规范的面向方面的编程实现,让你能够定义,例如方法拦截器(method-interceptors)和切点(pointcuts),从逻辑上讲,从而减弱代码的功能耦合,清晰的被分离开。并且,利用source-level的元数据功能,还能够将各类行为信息合并到你的代码中。
  • Spring Web:Spring中的 Web 包提供了基础的针对Web开发的集成特性,例如多方文件上传,利用Servlet listeners进行IOC容器初始化和针对Web的ApplicationContext。当与WebWork或Struts一块儿使用Spring时,这个包使Spring可与其余框架结合。
  • Spring Web MVC:Spring中的MVC封装包提供了Web应用的Model-View-Controller(MVC)实现。Spring的MVC框架并非仅仅提供一种传统的实现,它提供了一种清晰的分离模型,在领域模型代码和Web Form之间。而且,还能够借助Spring框架的其余特性。

12. Spring中的设计模式

spring中经常使用的设计模式达到九种,咱们举例说明:

第一种:简单工厂

又叫作静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。 简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该建立哪个产品类。 spring中的BeanFactory就是简单工厂模式的体现,根据传入一个惟一的标识来得到bean对象,可是否是在传入参数后建立仍是传入参数前建立这个要根据具体状况来定。

第二种:工厂方法(Factory Method)

一般由应用程序直接使用new建立新的对象,为了将对象的建立和使用相分离,采用工厂模式,即应用程序将对象的建立及初始化职责交给工厂对象。通常状况下,应用程序有本身的工厂对象来建立bean.若是将应用程序本身的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean。

第三种:单例模式(Singleton)

保证一个类仅有一个实例,并提供一个访问它的全局访问点。
spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是由于spring管理的是是任意的java对象。

第四种:适配器(Adapter)

在Spring的Aop中,使用的Advice(通知)来加强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式(一、JDK动态代理。二、CGLib字节码生成技术代理。)对类进行方法级别的切面加强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,经过执行拦截器重的内容加强了代理方法的功能,实现的面向切面编程。

第五种:包装器(Decorator)

在咱们的项目中遇到这样一个问题:咱们的项目须要链接多个数据库,并且不一样的客户在每次访问中根据须要会去访问不一样的数据库。咱们以往在spring和hibernate框架中老是配置一个数据源,于是sessionFactory的dataSource属性老是指向这个数据源而且恒定不变,全部DAO在使用sessionFactory的时候都是经过这个数据源访问数据库。可是如今,因为项目的须要,咱们的DAO在访问sessionFactory的时候都不得不在多个数据源中不断切换,问题就出现了:如何让sessionFactory在执行数据持久化的时候,根据客户的需求可以动态切换不一样的数据源?咱们能不能在spring的框架下经过少许修改获得解决?是否有什么设计模式能够利用呢? 首先想到在spring的applicationContext中配置全部的dataSource。这些dataSource多是各类不一样类型的,好比不一样的数据库:Oracle、SQL Server、MySQL等,也多是不一样的数据源:好比apache 提供的org.apache.commons.dbcp.BasicDataSource、spring提供的org.springframework.jndi.JndiObjectFactoryBean等。而后sessionFactory根据客户的每次请求,将dataSource属性设置成不一样的数据源,以到达切换数据源的目的。
spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另外一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。

第六种:代理(Proxy)

为其余对象提供一种代理以控制对这个对象的访问。 从结构上来看和Decorator模式相似,但Proxy是控制,更像是一种对功能的限制,而Decorator是增长职责。
spring的Proxy模式在aop中有体现,好比JdkDynamicAopProxy和Cglib2AopProxy。

第七种:观察者(Observer)

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都获得通知并被自动更新。
spring中Observer模式经常使用的地方是listener的实现。如ApplicationListener。

第八种:策略(Strategy)

定义一系列的算法,把它们一个个封装起来,而且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

第九种:模板方法(Template Method)

定义一个操做中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类能够不改变一个算法的结构便可重定义该算法的某些特定步骤。
Template Method模式通常是须要继承的。这里想要探讨另外一种对Template Method的理解。spring中的JdbcTemplate,在用这个类时并不想去继承这个类,由于这个类的方法太多,可是咱们仍是想用到JdbcTemplate已有的稳定的、公用的数据库链接,那么咱们怎么办呢?咱们能够把变化的东西抽出来做为一个参数传入JdbcTemplate的方法中。可是变化的东西是一段代码,并且这段代码会用到JdbcTemplate中的变量。怎么办?那咱们就用回调对象吧。在这个回调对象中定义一个操纵JdbcTemplate中变量的方法,咱们去实现这个方法,就把变化的东西集中到这里了。而后咱们再传入这个回调对象到JdbcTemplate,从而完成了调用。这多是Template Method不须要继承的另外一种实现方式吧。

13.ApplicationContext与BeanFactory的区别

二者都是经过xml配置文件加载bean,ApplicationContextBeanFacotry相比,提供了更多的扩展功能,但其主要区别在于后者是延迟加载,若是Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常;而ApplicationContext则在初始化自身是检验,这样有利于检查所依赖属性是否注入;因此一般状况下咱们选择使用ApplicationContext。

BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,咱们就不能发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性建立了全部的Bean。这样,在容器启动时,咱们就能够发现Spring中存在的配置错误。

BeanFactoryApplicationContext都支持BeanPostProcessorBeanFactoryPostProcessor的使用,但二者之间的区别是:BeanFactory须要手动注册,而ApplicationContext则是自动注册

14. 如何理解IoC和DI?

IOC:
IOC就是控制反转,通俗的说就是咱们不用本身建立实例对象,这些都交给Spring的bean工厂帮咱们建立管理。这也是Spring的核心思想,经过面向接口编程的方式来是实现对业务组件的动态依赖。这就意味着IOC是Spring针对解决程序耦合而存在的。在实际应用中,Spring经过配置文件(xml或者properties)指定须要实例化的java类(类名的完整字符串),包括这些java类的一组初始化值,经过加载读取配置文件,用Spring提供的方法(getBean())就能够获取到咱们想要的根据指定配置进行初始化的实例对象。

  • 优势:IOC或依赖注入减小了应用程序的代码量。它使得应用程序的测试很简单,由于在单元测试中再也不须要单例或JNDI查找机制。简单的实现以及较少的干扰机制使得松耦合得以实现。IOC容器支持勤性单例及延迟加载服务。

DI:DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并不是为软件系统带来更多功能,而是为了提高组件重用的频率,并为系统搭建一个灵活、可扩展的平台。经过依赖注入机制,咱们只须要经过简单的配置,而无需任何代码就可指定目标须要的资源,完成自身的业务逻辑,而不须要关心具体的资源来自何处,由谁实现。

15.介绍一下AOP相关术语?

  • 切面(Aspect):被抽取的公共模块,可能会横切多个对象。 在Spring AOP中,切面可使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。
  • 链接点(Join point):指方法,在Spring AOP中,一个链接点 老是 表明一个方法的执行。
  • 通知(Advice):在切面的某个特定的链接点(Join point)上执行的动做。通知有各类类型,其中包括“around”、“before”和“after”等通知。许多AOP框架,包括Spring,都是以拦截器作通知模型, 并维护一个以链接点为中心的拦截器链。
  • 切入点(Pointcut):切入点是指 咱们要对哪些Join point进行拦截的定义。经过切入点表达式,指定拦截的方法,好比指定拦截add、search
  • 引入(Introduction):(也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。Spring容许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
  • 目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫作 被通知(adviced) 对象。 既然Spring AOP是经过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
  • 织入(Weaving):指把加强应用到目标对象来建立新的代理对象的过程。Spring是在运行时完成织入。

切入点(pointcut)和链接点(join point)匹配的概念是AOP的关键,这使得AOP不一样于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如,一个提供声明式事务管理的around通知能够被应用到一组横跨多个对象中的方法上(例如服务层的全部业务操做)。

AOP相关术语

16.你是如何理解Spring AOP?

概念

面向切面编程。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,利用AOP能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度下降,提升程序的可重用性,同时提升了开发的效率。

核心思想
能够在不修改源代码的前提下,对程序进行加强

实现原理
Spring框架的AOP技术底层也是采用的代理技术,所谓的动态代理就是说 AOP 框架不会去修改字节码,而是在内存中临时为方法生成一个 AOP 对象,这个 AOP 对象包含了目标对象的所有方法,而且在特定的切点作了加强处理,并回调原对象的方法 。Spring AOP 中的动态代理主要有两种方式, JDK 动态代理和 CGLIB 动态代理 。

  • JDK 动态代理:经过反射来接收被代理的类,而且要求被代理的类必须实现一个接口 。JDK 动态代理的核心是 InvocationHandler 接口和 Proxy 类 。
  • CGLIB动态代理: 若是目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类 。CGLIB ( Code Generation Library ),是一个代码生成的类库,能够在运行时动态的生成某个类的子类,注意, CGLIB 是经过继承的方式作的动态代理,所以若是某个类被标记为 final ,那么它是没法使用 CGLIB 作动态代理的。

17. Spring中有哪些加强处理,区别?

  • 前置加强:org.springframework.aop.BeforeAdvice表明前置加强,表示在目标方法整形前实施加强
  • 后置加强:org.springframework.aop.AfterReturningAdvice表明后置加强,表示在目标方法执行后实施加强
  • 环绕加强:org.springframework.aop.MethodInterceptor表明环绕加强,表示在目标方法执行先后实施加强
  • 异常抛出加强 :org.springframework.aop.ThrowsAdvice表明抛出异常加强,表示在目标方法抛出异常后实施加强
  • 引介加强:org.springframework.aop.IntroductionInterceptor表明引介加强,表示在目标类中添加一些新的方法和属性

18. Spring中支持的Bean做用域有哪些?

支持以下五种不一样的做用域

  • Singleton(默认):在Spring IOC容器中仅存在一个Bean实例,Bean以单实例的方式存在。
  • Prototype:一个bean能够定义多个实例
  • Request:每次HTTP请求都会建立一个新的Bean。该做用域仅适用于WebApplicationContext环境。
  • Session:一个HTTP Session定义一个Bean。该做用域仅适用于WebApplicationContext环境.
  • GolbalSession:同一个全局HTTP Session定义一个Bean。该做用域一样仅适用于WebApplicationContext环境.

19.如何定义bean的做用域?

Spring中建立一个bean的时候,咱们能够声明它的做用域。只须要在bean定义的时候经过scope属性定义便可。例如,当Spring须要产生每次一个新的bean实例时,应该声明beanscope属性为prototype。若是每次你但愿Spring返回一个实例,应该声明beanscope属性为singleton

20.说一说Spring框架中的bean的生命周期?

  • Spring容器读取XML文件中bean的定义并实例化bean。
  • Spring根据bean的定义设置属性值。
  • 若是该Bean实现了BeanNameAware接口,Spring将bean的id传递给setBeanName()方法。
  • 若是该Bean实现了BeanFactoryAware接口,Spring将beanfactory传递给setBeanFactory()方法。
  • 若是任何bean BeanPostProcessors 和该bean相关,Spring调用postProcessBeforeInitialization()方法。
  • 若是该Bean实现了InitializingBean接口,调用Bean中的afterPropertiesSet方法。若是bean有初始化函数声明,调用相应的初始化方法。
  • 若是任何bean BeanPostProcessors 和该bean相关,调用postProcessAfterInitialization()方法。
  • 若是该bean实现了DisposableBean,调用destroy()方法。

21.哪些是最重要的bean生命周期方法,是否能重写它们?

有两个重要的bean生命周期方法。

  • 第一个是setup方法,该方法在容器加载bean的时候被调用。
  • 第二个是teardown方法,该方法在bean从容器中移除的时候调用。

bean标签有两个重要的属性(init-method 和 destroy-method),你能够经过这两个属性定义本身的初始化方法和析构方法。
Spring也有相应的注解:@PostConstruct@PreDestroy

22.有几种不一样类型的自动代理?

BeanNameAutoProxyCreator
DefaultAdvisorAutoProxyCreator
Metadata autoproxying

23. 什么是Spring的内部bean?

当一个bean仅被用做另外一个bean的属性时,它能被声明为一个内部bean,为了定义inner bean,在Spring 的 基于XML的 配置元数据中,能够在 或 元素内使用 元素,内部bean一般是匿名的,它们的Scope通常是prototype。

24. Spring中自动装配的方式有哪些?

  • no:不进行自动装配,手动设置Bean的依赖关系。
  • byName:根据Bean的名字进行自动装配。
  • byType:根据Bean的类型进行自动装配。
  • constructor:相似于byType,不过是应用于构造器的参数,若是正好有一个Bean与构造器的参数类型相同则能够自动装配,不然会致使错误。
  • autodetect:若是有默认的构造器,则经过constructor的方式进行自动装配,不然使用byType的方式进行自动装配。
说明:自动装配没有自定义装配方式那么精确,并且不能自动装配简单属性(基本类型、字符串等),在使用时应注意。

25.你能够在Spring中注入null或空字符串吗?

彻底能够。

26. 不一样版本的 Spring Framework 有哪些主要功能?

Version Feature
Spring 2.5 发布于 2007 年。这是第一个支持注解的版本。
Spring 3 发布于 2009 年。它彻底利用了 Java5 中的改进,并为 JEE6 提供了支持。
Spring 4.0 发布于 2013 年。这是第一个彻底支持 JAVA8 的版本。。

27.spring DAO 有什么用?

Spring DAO 使得 JDBC,Hibernate 或 JDO 这样的数据访问技术更容易以一种统一的方式工做。这使得用户容易在持久性技术之间切换。它还容许您在编写代码时,无需考虑捕获每种技术不一样的异常。

28. 列举 Spring DAO 抛出的异常。

spring-data-access-exception

29. spring JDBC API 中存在哪些类?

  • JdbcTemplate
  • SimpleJdbcTemplate
  • NamedParameterJdbcTemplate
  • SimpleJdbcInsert
  • SimpleJdbcCall

30.Spring AOP and AspectJ AOP 有什么区别?

Spring AOP 基于动态代理方式实现;AspectJ 基于静态代理方式实现。
Spring AOP 仅支持方法级别的 PointCut;提供了彻底的 AOP 支持,它还支持属性级别的 PointCut。

推荐

大厂笔试内容集合(内有详细解析) 持续更新中....

ProcessOn是一个在线做图工具的聚合平台~

文末

欢迎关注我的微信公众号: Coder编程
欢迎关注 Coder编程公众号,主要分享数据结构与算法、Java相关知识体系、框架知识及原理、Spring全家桶、微服务项目实战、DevOps实践之路、每日一篇互联网大厂面试或笔试题以及PMP项目管理知识等。更多精彩内容正在路上~
新建了一个qq群:315211365,欢迎你们进群交流一块儿学习。谢谢了!也能够介绍给身边有须要的朋友。

文章收录至
Github: https://github.com/CoderMerli...
Gitee: https://gitee.com/573059382/c...
欢迎关注并star~
微信公众号

相关文章
相关标签/搜索