【Java】Spring面试题总结

目录

✅什么是Spring?你的理解是什么?

✅Spring的优缺点

✅解释一下IOC和AOP

✅IOC和DI的区别?

✅Spring中管理 / 注入对象的方式

✅常用注解

✅Spring中的 bean 和 new 的对象有什么区别?

✅AOP中的属于有哪些?通知有哪些?

✅谈谈Spring事务管理,实现方式有几种,原理是什么?

✅声明式事务哪些场景下会失效?

✅SpringMVC运行流程

✅Servlet的过滤器与Spring拦截器区别?

✅Spring和SpringBoot关系

✅Spring中Bean的生命周期

✅Spring中Bean的线程安全的吗?

✅Bean依赖循环

✅Spring中是如何解决循环依赖的问题的?

✅SpringBoot自动装配原理


✅什么是Spring?你的理解是什么?

是一个轻量级的,开源的,一站式的Java开发框架,为简化企业级开发而生

✅Spring的优缺点

优点:

轻量级,开源的,简单,IOC和AOP

缺点:

配置麻烦,很多都是模板化配置,管理很多依赖

✅解释一下IOC和AOP

IOC:

控制反转,把项目中创建对象的权利反转给Spring框架,由Spring框架统一管理项目中的对象,把由Spring框架生成的对象称为一个bean对象,Spring可以对对象进行功能上的增强。例如Service层可以添加日志、事务管理。

AOP:

面向切面编程,使用动态代理的方式,为目标对象提供代理对象,在不修改目标类中的代码时,为目标类添加额外的功能。将额外的功能横切到目标类中。

✅IOC和DI的区别?

IOC上一问回答过了

DI:

Dependency Injection,即依赖注入,@Autowired,在IOC的基础上,把对象注入到需要的地方

✅Spring中管理 / 注入对象的方式

xml配置方式,注解方式

属性注入(Set方法注入),构造方法注入

✅常用注解

▪ 控制层 @RestController

▪ 数组访问层 @Repository

▪ 基本组件 @Component

......(其余参考文档)

✅Spring中的 bean 和 new 的对象有什么区别?

bean对象是由Spring框架创建的,根据我们的配置可以进行功能上的增强。配置比如说事务、日志、统一异常处理等。

自己new的对象就是最原始的对象,没有任何功能增强。

✅AOP中的属于有哪些?通知有哪些?

▪ 属性

连接点:类中可以被增强的方法

切入点:类中实际被增强的方法

通知:给切入点添加的功能

目标:被增强的类

代理:代理对象

▪ 通知类型

前置通知:方法执行前执行

后置通知:在方法执行后执行,即使出现异常也会执行

返回通知:也是在方法执行后执行,但一旦出现异常就不会执行

异常通知:出异常时执行

环绕通知:可以实现以上四个通知

✅谈谈Spring事务管理,实现方式有几种,原理是什么?

事务是数据库的特性,Spring事务管理只是Spring框架对事务开启,提交,回滚进行管理

▪ 编程式事务:需要在代码中自己提交,回滚

▪ 声明式事务:在类、方法上声明即可,使用@Transactional(rollbackFor = Exception.class)

使用动态代理对象

✅声明式事务哪些场景下会失效?

▪ @Transactional用在非public方法上

▪ 方法中的异常被捕获了,认为方法没有异常

▪ 方法中出现编译期异常,还是会提交事务,可以将 rollbackFor = Exception.class 这样所有的异常都会回滚

▪ 数据库引擎不支持事务,mysql中只有InnoDB引擎支持事务的

✅SpringMVC运行流程

✅Servlet的过滤器与Spring拦截器区别?

✅Spring和SpringBoot关系

SpringBoot是对Spring框架的搭建进行封装,简化了搭建过程,不是替代Spring的,底层仍然还是Spring

✅Spring中Bean的生命周期

宏观上来讲可分为五个阶段:

▪ 实例化 Instantiation

▪ 属性赋值 Populate (依赖注入)

▪ 初始化 Initialization (最关键的,根据我们各种的注解配置,在这一步进行落地实现)

▪ 将bean对象放到容器中,使用

▪ 销毁 Destruction

✅Spring中Bean的线程安全的吗?

这个问题需要分情况回答,要根据使用场景

单例Bean

▪ Spring中的Bean如果是单例的,始终只创建了一个对象,所有请求共用同一个对象,那么对该单例对象中的成员变量也就只有一份,所有请求共享。

▪ 在多用户访问时,可能出现问题,还有种情况就是每个请求中都拥有一个属于自己的成员变量使用。

▪ 所以单例Bean在使用时就有可能存在线程安全的问题

原型Bean

▪ 原型Bean每次请求都会创建新的对象,不会存在线程安全的问题

单例Bean线程安全问题解决:

▪ 如果成员变量是共享的,多线程操作时,如++等操作需要进行加锁控制

▪ 如果每个请求在中都需要一个属于自己的成员变量,可以把单例Bean改为原型,也可以使用ThreadLocal,为每次请求提供变量副本。

单例Bean又分为:

▪ 有状态的Bean。就是有成员变量,而且成员变量可以存储数据,就是可能在多线程操作时会出现问题

▪ 无状态的Bean。像通过@Autowired 注入的对象不用于存储数据,只是调方法,每次请求中的参数数据都是隔离的,多线程也是安全的

✅Bean依赖循环

在Spring中,如果使用@Autowired自动注入,在创建A对象时就需要为它关联的B对象注入值,这时就需要去创建对象B,创建B时又需要为关联的A注入值,但是此时A还没创建完成,形成死循环。

class A{
    @Autowired
    B b;
}
​
class B{
    @Autowired
    A a;
}
​
public static void main(String[] args){
    A a = new A();
    B b = new B();
}

Spring中是如何解决循环依赖的问题的?

Spring中使用三级缓存来解决循环依赖问题

▪ 一级缓存(singletonObject),一级缓存对象,主要存储创建,初始化完成的Bean对象

▪ 二级缓存(earlySingletonObject),主要存储实例化完成,但还未初始化完成的半成品对象

▪ 三级缓存(SingletonFactories),主要存储创建对象的工厂对象,创建A时,还有一个创建A的 工厂对象

过程描述:创建A时,需要用到B,A创建了一半,把它存放到二级缓存中,把创建A工厂放到三级缓存中,把半成品A注入到B中,B完成了创建,把B放到了一级缓存中,再把B注入到A中,A对象完成了创建。

✅SpringBoot自动装配原理

从启动类说起

@SpringBootApplication 注解标签,里面包含了三个注解标签

@SpringBootConfiguration
@EnableAutoConfiguration  //自动配置
@ComponentScan(  //扫描启动类所在的包下的类
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

约定大于配置