Spring常见面试题整理

1、Spring是什么?

Sprin是一个轻量级的IOC和AOP容器框架,它能够解决企业级应用开发的业务逻辑层和其他各层之间的耦合问题,简化企业级应用程序开发的复杂性,即简化Java开发。
Spring有两个核心特性分别是:IOC(控制反转)和AOP(面向切面编程)。

2、使用Spring有什么优点?解释一下为什么要使用Spring?

(1)方便解耦,简化开发
Spring就像是一个大工厂,可以将所有对象的创建和依赖关系的维护都交给Spring管理,从而减低组件的耦合性;
(2)AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控、扩展程序功能等等;
(3)声明式事务的支持
只需要通过配置就可以完成对事务的管理,无需手动编程;
(4)方便程序的测试
Spring对Junit4的支持,可以通过注解方便的测试Spring程序;
(5)方便集成各种优秀的框架

3、Spring有哪些主要模块?

(1)Spring Core :框架最基础的部分,提供IOC容器,对bean进行管理;

(2)Spring Context:基于bean,提供上下文对象,扩展出JNDI、EJB、电子邮件、校验调度等功能。

(3)Spring DAO:提供了JDBC的抽象层,它可以消除冗(rong)长的JDBC编码和解析数据库厂商特有的错误代码,还提供了声明式事务管理方法。

(4)Spring ORM:提供了常用的“对象/关系”映射APIs的集成。其中包括JPA、JDO、Mybatis等。

(5)Spring AOP:提供了符合AOP Alliance规范的面向切面的编程实现。

(6)Spring Web:提供了基础的Web开发的上下文信息,可与其他web进行集成。

(7)Spring Web MVC:提供了Web应用的Model-View-Controller全功能的实现。

4、介绍一下SpringIOC,使用IOC有什么好处?

IOC,Inversion of Control(控制反转),它是一种设计思想,就是将你设计好的对象交给容器控制,而不是自己去创建。把创建和查找依赖对象的控制权交给IOC容器,由IOC容器进行注入、组合对象。

优点:实现了对象与对象之间的松耦合、便于测试、功能可复用,减少了对象的创建和内存的消耗,使得程序的整体结构变得更方便维护、灵活性更高、扩展性更强。

大白话解释:
IOC就是控制反转,就是让一个对象的创建不用自己去new了,使用Spring之后对象可以自动的产生,这其实就是利用了java中的反射,反射其实就是在运行时动态的去创建、调用对象,Spring就是在运行的时候,在Spring的配置文件,也就是XML文件中来动态的创建对象和调用对象中的方法。

ioc的思想最核心的地方在于,资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。
第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。

举例子说:
比如甲方需要一双袜子,而乙方它卖一双袜子,它要把袜子卖出去,但是乙方要告诉别人我要卖一双袜子。甲乙双方进行交易活动,但是他们都不需要自己直接去找卖家,相当于程序内部开放接口,卖家由第三方作为参数传入。甲乙互相不依赖,而且只有在进行交易活动的时候,甲才和乙产生联系。反之亦然。这样做什么好处么呢,甲乙可以在对方不真实存在的情况下独立存在,而且保证不交易时候无联系,想交易的时候可以很容易的产生联系。甲乙交易活动不需要双方见面,避免了双方的互不信任造成交易失败的问题。因为交易由第三方来负责联系,而且甲乙都认为第三方可靠。那么交易就能很可靠很灵活的产生和进行了。

5、SpringIOC创建对象的方式有哪些?

(1)通过无参构造器创建对象;
(2)通过有参构造器创建对象;
(3)通过工厂模式创建对象。

6、SpringIOC的三种注入方式分别是什么?

(1)通过构造器注入;
(2)通过set方法注入;
(3)通过注解自动注入;

7、介绍一下Spring AOP。

AOP全名为Aspect Oriented Programming,面向切面编程。
作为面向对象的一种补充,用于将那些与业务无关,但是却对多个对象产生影响的公共行为和逻辑,抽取并封装成一个可重用的模块,这个模块被命名为切面(Aspect),减少了系统的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。

SpringAOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表就是AspectJ;动态代理则以SpringAOP为代表。

8、Spring AOP中的几个名词解释。

(1)切面(Aspect):切面其实就是切点和通知的结合。切点和通知共同定义了切面中的内容,在SpringAOP中切面可以使用通用类(基于模板风格)或者是在普通类中使用@AspectJ注解来实现。

(2)连接点(Join point):指的是方法,在SpringAOP中一个连接点总是代表着一个方法的执行。

(3)通知(Advice):在切面上某个连接点上执行的动作,通俗的说就是我们需要扩展的功能代码,通知又分为前置通知(before)、后置通知(after)、环绕通知(around)、异常通知等。

(4)切入点(Pointcut):指的是我们需要对哪些连接点进行拦截,通过切入点表达式可以指定拦截的方法。

(5)引入(Introduction):引入允许我们想现有类添加新方法或者属性;

(6)目标对象(Target Object):被一个或者多个切面所通知的对象。通常为一个代理对象。

(7)织入(Weaving):织入就是把切面应用到目标对象并创建新的代理对象的过程,Spring在运行时完成织入。

9、介绍一下SpringAOP的动态代理模式。

SpringAOP的动态代理模式主要有两种,分别是JDK动态代理和CGLIB动态代理。
(1)JDK动态代理只提供接口的代理,不支持类代理。核心为InvocationHandler接口和Proxy类,InvocationHandler接口通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务逻辑编织在一起,接着Proxy就利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

(2)CGLIB动态代理,代理类没有实现InvocationHandler接口,它是一个代码生成的类库,可以在运行时动态地生产指定类的一个子类对象,并且覆盖其中特定方法来增强代码,从而实现代理;CGLIB是通过继承的方式做的动态代理,如果某个类被标记为final,那么它就无法使用CGLIB做动态代理的。

静态代理和动态代理的区别在于生成代理对象的时机不一样,相对来说静态代理AspectJ的静态代理方式具有更好的性能。

10、Spring的bean是什么?它是线程安全的吗?

Spring bean是那些形成Spring应用主干的Java对象,它们被SpringIOC容器初始化、装配和管理,这些beans通过在容器中配置的元数据创建。
默认的Spring容器中的bean是单例的,当单例中存在竞争条件时,会有线程安全问题。
Spring管理的bean的线程安全跟bean的创建作用域和bean所在的使用环境是否存在竞争有关,Spring并不能保证bean的线程安全。

11、Spring支持几种bean的作用域?

(1)Singleton:单例模式,在整个SpringIOC容器中,使用singleton定义的bean只有一个实例;

(2)prototype:原型模式,每次通过容器的getbean方式获取prototype定义的bean时,都产生了一个新的bean实例。

只有在Web应用中使用Spring时,request、session、global-session作用域才会生效。
(3)request:对于每次HTTP请求,使用request定义的bean都将产生一个新实例,即每次HTTP请求将会产生不同的bean实例。

(4)session:同一个Session共享一个bean实例。

(5)global-session:同session作用域不同的是,所有的Session共享一个Bean实例。

12、Spring自动装配bean有哪些方式?

(1)no方式,默认的方式,不自动装配,需要使用到节点或者参数;

(2)byName:根据bean的名称进行装配;

(3)byType:通过参数的数据类型进行装配;

(4)constructor:根据构造函数进行装配。

(5)Spring配置文件中节点的Autowire参数可以控制bean自动装配的方式。

13、介绍一下Spring支持的事务管理类型?

Spring支持两种两种事物管理,一种是编程式事务管理,另外一种是声明式事务管理。
(1)编程式事务管理:指的是通过编码方式实现事务,允许用户在代码中精确定义事务的边界。即类似于JDBC编程实现事务管理。

(2)声明式事务管理:管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。

声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

14、介绍一下Spring的事务隔离级别?(重点)

Spring有五大事务隔离级别,其中Spring默认的事务隔离级别为:ISOLATION_DEFAULT(使用的是数据库的设置),其他的四个事务隔离级别和数据库的隔离级别一致。
(1)ISOLATION_DEFAULT:用的底层数据库的设置隔离级别,数据库设置的是什么就用什么。

(2)ISOLATION_READ_UNCOMMITTED:未提交读,最低的事务隔离级别,事务未提交前就可以被其他事务读取,会出现幻读、脏读,不可重复读。

(3)ISOLATION_READ_COMMITTED :已提交读,一个事务提交后才能被其他事务读取到(可能会造成幻读、不可重复读),SQL Server的默认级别(Oracle的默认隔离级别)。

(4)ISOLATION_REPEATABLE_READ:可重复读,保证多次读取同一个数据时,其值都和事务开始的时候的内容一致,禁止读取到别的事务未提交的数据(可能会造成幻读),这是MYSQL的默认隔离级别。

(5)ISOLATION_SERIALIZABLE:序列化,代价最高的但是最可靠的隔离级别,该级别能够防止脏读、不可重复读、幻读。

脏读:表示一个事务能够读取另一个事务未提交的数据;
幻读:指的是同一个事务多次查询返回的结果集不一样。
不可重复读:指的是在一个事务中多次读取同一个数据。

15、介绍一下关于事务的四个特性(ACID)

事务有四个特性(ACID),分别是原子性、一致性、隔离性、持久性。
(1)原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性能够确保动作(增、删、改)要么全部完成,要么不起作用。

(2)一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败,在现实中的数据不应该被破坏。

(3)隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,以此防止数据损坏。

(4)持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下事务的结果被写到持久化存储器中。

16、Spring的事务传播行为介绍

Spring的事务传播行为说的是当多个事务同时存在的时候,Spring是如何处理这些事务的行为的。
(1)PROPAGATION_REQUIRED:如果当前没有事务就创建一个新的事务,如果当前存在事务就加入该事务,该设置是最常用的设置,同时也是默认值;

(2)PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务就加入当前事务,如果当前不存在事务就以非事务执行;

(3)PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务就加入该事务,如果当前不存在事务就抛出异常;

(4)PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务都创建新事务;

(5)PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起;

(6)PROPAGATION_NEVER:以非事务的方式执行,如果当前存在事务,则抛出异常;

(7)PROPAGATION_NESTED:如果当前存在事务,则嵌套事务内执行,如果当前没有事务就按REQUIRED属性执行。

17、Spring的注解介绍

Spring常见的注解及其作用:
(1)@Conponent:创建类对象,相当于配置,bean的ID默认为类名首字母小写,同时也可以指定ID,例如@Conponent(“stu”);

(2)@Service:作用和@Conponent一样,创建类对象,但是它是作用在业务层实现类上;

(3)@Repository:作用和@Conponent一样,也是创建类对象,但是它是作用在数据访问层上;

(4)@Controller:作用和@Conponent一样,创建类对象,作用在控制器类上;

(5)@Resource:使用了这个注解之后就不需要写对象的get/set方法了,它是Java的注解,默认是按照byName方式注入,如果没有名称对象就按照byType注入,使用这个注解的时候建议把对象名称写成和Spring容器中对象名一致。

(6)@Autowired:自动注入,使用了这个注解同样不需要写对象的get、set方法了,它是Spring的注解,同样也是最常用的注解之一,默认是按照byType进行注入。

(7)@Value():这个注解是获取properties配置文件中的内容。

(8)@RequestMapping:此注解用于将特定的HTTP请求映射到将处理相应请求的控制器中的特定类/方法。此注解可应用于两个级别:
A、类级别:映射请求的URL;
B、方法级别:映射URL以及HTTP请求方法。

(9)@Configuration:该注解用于定义配置类,可替换xml配置文件,被该注解标注的类内部包含一个或者多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,从而初始化Spring容器。
@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的,作用为:配置spring容器(应用上下文)。

18、 @Autowired 、 @Inject、@Resource 之间有什么区别?

(1)@Autowired是Spring提供的注解,而@Inject和@Resource是java规范的;
(2)@Autowired和@Inject基本是一样的,都是使用AutowiredAnnotationBeanPostProcessor来处理依赖注入,但是@Resouece是个例外,它是由CommonAnnotationBeanPostProcessor来处理依赖注入的;
(3)@Autowired是spring实现的,@Inject是jsr330实现的,@Resouece是jsr250实现的。

19、@Configuration 如何嵌套?@Configuration 使用上有哪些约束?

@Configuration注解作用在类上,就和普通类一样能够进行相互嵌套,定义内部类就可以进行相互嵌套。
这个注解的使用约束如下所示:
(1)必须以类的方式提供(而不是从工厂方法返回的实例);
(2)被@Configuration注解的类必须是非final的;
(3)任何嵌套的@Configuration都必须是static的;
(4)@Bean方法可能不会反过来创建更多配置类;
(5)配置类必须是本地的(可能不在方法中声明),native标注的方法。

20、Spring项目怎么进行单元测试?

首先加载Spring的jar包,Spring-test-4.0.4-RELEASE.jar和commons-logging-1.2.jar
然后再applicationContext.xml中扫描service实现包,
<context:component-scan base-package=“service.impl”></context:component-scan>
之后在UserServiceImpl实现类上使用springmvc 注解@Service(“userService”)
编写spring单元测试,点击运行。
在这里插入图片描述

@RunWith(SpringJUnit4ClassRunner.class) 上面已做介绍。
@ContextConfiguration(locations={“classpath:applicationContext.xml”})加载配置文件,locations参数是一个数组,可以加载多个,配置文件。
@Resource 自动注入Ioc容器的对应的bean。
@Test 我们的测试方法。

21、Spring 框架中都用到了哪些设计模式?

(1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;

(2)单例模式:Bean默认为单例模式。

(3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;

(4)模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。

(5)观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,
所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener。

22、Spring如何处理线程并发问题?

在一般情况下,只有无状态的Bean才可以在多线程环境下共享,
在Spring中,绝大部分Bean都可以声明为singleton作用域,
因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

23、Spring项目是如何启动的?

在这里插入图片描述
如上图所示,Spring项目在启动时,首先会去读取应用程序提供的Bean配置信息,并且会在Spring容器中生成一份对应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系,为上层应用提供准备就绪的运行环境。

关于图中步骤的详细说明:
第一步:读取Bean的配置信息,对于Bean的配置有很多种方式,比如说可以在Spring的XML文件当中使用标签声明一个bean,除此之外还可以在Java的类当中使用@Configuration注解来标识它是一个配置类,还可以通过@Autowired注解来完成一个对象的注入配置,这些信息肯定是要Spring去读取的;

第二步:Spring启动读到Bean配置文件解析出来的信息之后,会将读取到的需要注册的Bean加到Spring容器中(就是IOC容器),在里面会形成一个Bean定义的注册表,然后Spring会根据注册表里面的信息将Bean对象进行实例化,把配置的Bean都要做一次实例化,在实例化的过程中完成依赖注入。

第三步:之后便是将已经实例化的Bean对象放回Spring的容器当中,放到Bean的缓存池里,当我们应用程序需要用到这个Bean的时候,就会调用getBean方法去缓存池中调用。其实都是去的Spring容器中的Bean缓存池里去取的Bean对象。

目前尚未理解的问题有以下:

24、Spring如何对Bean进行延迟初始化?
25、@Profile有什么用?
26、Spring是如何处理带@Configuration @Import的类?
27、@Configuration和XML有什么区别?哪种好?

如有对以上问题有所建议,请在评论区讨论哈,大家一起学习学习!

你现在的每一刻努力,都有可能是未来的你在向你求救。

猜你喜欢

转载自blog.csdn.net/weixin_43246215/article/details/107419321