Spring面试题总结
1. 什么是Spring框架?
Spring 是⼀种轻量级开发框架,旨在提⾼开发⼈员的开发效率以及系统的可维护性。我们⼀般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使⽤这些模块可以很⽅便地协助我们进⾏开发。
2. 列举一些重要的Spring模块?
- spring core:框架的最基础部分,提供 ioc 和依赖注入特性。
- spring context:构建于 core 封装包基础上的 context 封装包,提供了一种框架式的对象访问方法。
- spring dao:Data Access Object 提供了 JDBC 的抽象层。
- spring aop:提供了面向切面的编程实现,让你可以自定义拦截器、切点等。
- spring Web:提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。
- spring Web mvc:spring 中的 mvc 封装包提供了 Web 应用的 Model-View-Controller (MVC)的实现。
3. IOC的理解?
3.1 什么是IOC?
控制反转,指将对象的控制权转移给Spring框架,由 Spring 来负责控制对象的生命周期(比如创建、销毁)和对象间的依赖关系。
3.2 理解
最直观的表达就是,以前创建对象的时机和主动权都是由自己把控的,如果在一个对象中使用另外的对象,就必须主动通过new指令去创建依赖对象,使用完后还需要销毁(比如Connection等),对象始终会和其他接口或类耦合起来。而 IOC 则是由专门的容器来帮忙创建对象,将所有的类都在 Spring 容器中登记,当需要某个对象时,不再需要自己主动去 new 了,只需告诉 Spring 容器,然后 Spring 就会在系统运行到适当的时机,把你想要的对象主动给你。也就是说,对于某个具体的对象而言,以前是由自己控制它所引用对象的生命周期,而在IOC中,所有的对象都被 Spring 控制,控制对象生命周期的不再是引用它的对象,而是Spring容器,由 Spring 容器帮我们创建、查找及注入依赖对象,而引用对象只是被动的接受依赖对象,所以这叫控制反转。
3.3 底层实现
工厂设计模式+反射机制
3.4 IOC的作用
- 管理对象的创建和依赖关系的维护。
- 解耦降低了依赖,由容器去维护具体的对象的创建。
- bean对象生命周期管理。
3.5 使用IOC容器的优点?
- IOC和DI的配合使用能把应用的实际代码量降到最低。
- spring集成了自己的测试模块,无需依赖于junit。
- IOC容器支持立即加载和延迟加载(懒加载)。
3.6 spring IOC支持哪些功能?
- 依赖注入
- 依赖检查
- 自动装配
- 支持集合
4. DI
4.1 什么是DI?
IOC 的一个重点就是在程序运行时,动态的向某个对象提供它所需要的其他对象,这一点是通过DI(Dependency Injection,依赖注入)来实现的,即应用程序在运行时依赖 IOC 容器来动态注入对象所需要的外部依赖。而 Spring 的 DI 具体就是通过反射实现注入的,反射允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性。
4.2 底层实现?
反射:setter方法+暴力反射Field对象
5. AOP
5.1 什么是AOP?
Spring AOP 的面向切面编程,是面向对象编程的一种补充,用于处理系统中分布的各个模块的横切关注点,比如事务管理、日志、缓存等.它是使用动态代理实现的,在内存中临时 为增强某个方法生成一个 AOP 对象,这个对象包含目标对象的所有方法,在特定的切入点做了增强处理,并回调原来的方法。
5.2 AOP能做什么?
- 降低模块的耦合度。
- 使系统容易扩展。
- 避免修改业务代码,避免引入重复代码,更好的代码复用。
5.3 AOP里面的几个名词的概念
- 连接点(Join point):指程序运行过程中所执行的方法。在Spring AOP中,一个连接点总代表一个方法的执行。
- 切面(Aspect):被抽取出来的公共模块,可以用来会横切多个对象。切面可以看成切点 和通知的结合,一个切面可以由多个切点和通知组成。
- 切点(Pointcut):切点用于定义要对哪些连接点进行拦截。
- 通知(Advice):指要在连接点上执行的动作,即增强的逻辑,比如权限校验和、日志记录等。
5.4 通知类型有哪些?
- 前置通知(Before Advice):在连接点之前执行的通知。
- 后置通知(After Advice):当连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
- 环绕通知(Around Advice):包围一个连接点的通知,这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也可以选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
- 返回后通知(AfterReturning Advice):在连接点正常完成后执行的通知(如果连接点抛出异常,则不执行)。
- 抛出异常后通知(AfterThrowing advice):在方法抛出异常退出时执行的通知。
6. Bean
6.1 Spring中Bean的作用域
Spring IOC 容器在根据配置创建一个 Bean 对象实例时,可以为 Bean 指定实例的作用范围。
-
singleton(单例模式)
IOC 容器仅创建一个 Bean 实例,IOC 容器每次返回的是同一个 Bean 实例。
-
prototype(原型模式)
IOC 容器仅创建多个 Bean 实例,IOC 容器每次返回的是一个新的实例
-
request(HTTP 请求)
该属性仅对 HTTP 请求产生作用,每次 HTTP 请求都会创建一个新的 Bean,适用于WebApplicationContext.
-
session(会话)
该属性仅用于 HTTP Session,同一个 session 共享一个 Bean 实例。不同 session 使用不同的实例。
-
global-session(全局会话)
该属性仅用于HTTP Session,同session作用域不同的时候,所有session共享一个Bean 实例。
6.2 Bean的生命周期
在实际开发中,我们一般常用的就是单例模式和原型模式。
单例模式生命周期和容器相同。
原型模式生命周期,是每次使用时创建新的对象,用完等待垃圾回收器回收。
6.3 Bean的实例化
- 构造方法实例化Bean
- 使用静态工厂实例化Bean
- 使用实例化工厂实例化Bean
- 使用FactoryBean实例化Bean
6.4 Spring 中的单例Bean的线程安全问题
Spring容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体情况还是要结合Bean的作用域来讨论。
对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。
如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。
对于有状态的bean,Spring官方提供的bean,一般在类中定义⼀个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中来解决线程安全问题。使用ThreadLocal,使得多线程场景下,多个线程对这个单例Bean的成员变量不存在资源的竞争,因为ThreadLocal为每个线程保存线程私有的数据。
6.5 底层实现?
反射+调用无参构造
7. Spring 框架中都用到了哪些设计模式?
- 工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例。
- 单例模式:Bean默认为单例模式。
- 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术。
- 模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
8. Spring的依赖注入
8.1 什么是Spring的依赖注入?
依赖关系的维护又称为依赖注入,这种关系交给spring来管理,当我们在类中要用到其它的类对象,都由spring来提供,我们只需要在配置文件中说明即可,依赖注入也是IOC控制反转的一种实现。
8.2 依赖注入有什么优势?
解耦,增加了模块的重用性灵活性。一般配置文件里存的都是数据,键值之类的。Spring的配置文件把要引用类和要给类传的参数都放到配置文件里,这样比以前写死在程序里更灵活,因此更具重用性。
8.3 构造器依赖注入和Setter方法注入的区别
构造器依赖注入 | Setter方法注入 |
---|---|
没有部分注入 | 有部分注入(提供setter) |
不会覆盖setter属性 | 会覆盖setter属性 |
任意修改都会创建新的实例 | 任意修改都不会创建新的实例 |
适用于设置很多属性 | 适用于设置少量属性 |
9. Spring的常用注解哪些?有什么作用?
9.1 将⼀个类声明为Spring的bean的注解有哪些?
-
@Component:通⽤的注解,可标注任意类为 Spring 组件。如果⼀个Bean不知道属于哪
个层,可以使⽤ @Component 注解标注。
-
@Repository : 对应持久层即 Dao 层,主要⽤于数据库相关操作。
-
@Service : 对应服务层,主要涉及⼀些复杂的逻辑,需要⽤到 Dao层。
-
@Controller : 对应 Spring MVC 控制层,主要⽤户接受⽤户请求并调⽤ Service 层返回数
据给前端⻚⾯。
9.2 @Autowired 注解有什么作用?
帮我们注入我们需要的对象,Spring会自动按照类型注入,只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。
9.3 @RequestMapping 注解有什么用?
用于接收HTTP请求,并将请求发送到相应的控制器类/方法上。作用位置有:
-
类:映射请求的URL父级目录
-
方法:映射URL和HTTP请求方法
9.4 @PropertySource 注解有什么用?
用于加载.properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。
9.5 @Value 注解有什么用?
用于注入基本类型和String类型的数据
9.6 @Import 注解有什么用?
用于导入其他的配置类
9.6 @Component 注解有什么用?
把当前类对象存入spring容器中
9.7 @ComponentScan 注解有什么用?
通过注解指定spring在创建容器时所要扫描的包
9.8 @Bean 注解有什么用?
用于把当前方法的返回值作为bean对象存入spring的ioc容器中
10. Spring的事务
10.1 事务最重要的两个特性?
- 事物的传播级别:定义了事务在传播方面的控制范围。
- 数据的隔离级别:定义了事务在数据读写方面的控制范围。
10.2 事务的7种传播级别?
- REQUIRED:默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。所以这个级别通常能满足处理大多数的业务场景。
- SUPPORTS:该传播级别的特点是,如果上下文存在事务,则支持事务加入事务,如果没有事务,则使用非事务的方式执行。通常是用来处理那些并非原子性的非核心业务逻辑操作。应用场景较少。
- MANDATORY:该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用这个传播级别。
- REQUIRES_NEW:该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。
- NOT_SUPPORTED:特点就是上下文中存在事务,则挂起事务,执行当前逻辑,结束后恢复上下文的事务。
- NEVER:要求上下文中不能存在事务,一旦有事务,就抛出runtime异常 ,强制停止执行!
- NESTED:嵌套级别事务。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。
10.3 数据隔离级别分为不同的四种:
- SERIALIZABLE:最严格的级别,事务串行执行,资源消耗最大;
- REPEATABLE READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
- READ COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
- READ UNCOMMITED:保证了读取过程中不会读取到非法数据。
脏读 | 读到了别的事务回滚前的脏数据。比如事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。 |
不可重复读 | 事务A首先读取了一条数据,然后执行逻辑的时候,事务B将这条数据改变了,然后事务A再次读取的时候,发现数据不匹配了,就是所谓的不可重复读了。 |
幻读 | 事务A首先根据条件索引得到10条数据,然后事务B改变了数据库一条数据,导致也符合事务A当时的搜索条件,这样事务A再次搜索发现有11条数据了,就产生了幻读。 |
10.4 事务管理底层
AOP