【面试题】Spring常见面试题整理2024(全是干货!!!)

备战实习,会定期给大家整理常考的面试题,大家一起加油! 🎯

注意:文章若有错误的地方,欢迎评论区里面指正 🍭 

系列文章目录

1、Spring是什么?

  • Spring是一种轻量级框架,旨在提高开发人员的开发效率以及系统的可维护性。

    我们一般说的Spring框架就是Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块是核心容器、数据访问/集成、Web、AOP(面向切面编程)、工具、消息和测试模块。比如Core Container中的Core组件是Spring所有组件的核心,Beans组件和Context组件是实现IOC和DI的基础,AOP组件用来实现面向切面编程。

    Spring官网列出的Spring的6个特征:

    • 核心技术:依赖注入(DI),AOP,事件(Events),资源,i18n,验证,数据绑定,类型转换,SpEL。
    • 测试:模拟对象,TestContext框架,Spring MVC测试,WebTestClient。
    • 数据访问:事务,DAO支持,JDBC,ORM,编组XML。
    • Web支持:Spring MVC和Spring WebFlux Web框架。
    • 集成:远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。
    • 语言:Kotlin,Groovy,动态语言。

2、列举一些重要的Spring模块?

  1. Spring Core:Spring框架的核心,提供了控制反转(IoC)容器和依赖注入(DI)功能。

  2. Spring Beans:定义了Spring的beans的配置方式,包括基于注解和XML的配置。

  3. Spring Context:提供了一种更加丰富的框架应用上下文,包括国际化、事件传播、资源访问等。

  4. Spring AOP:面向切面编程模块,允许开发者定义横切关注点,如日志记录、事务管理等。

  5. Spring DAO:数据访问对象模块,提供了对JDBC的抽象,简化了数据访问层的编码。

  6. Spring JDBC:提供了对Java数据库连接(JDBC)的抽象和简化,使得数据库操作更加方便。

  7. Spring ORM:对象关系映射模块,支持与Hibernate、JPA、MyBatis等ORM工具的集成。

  8. Spring TX:事务管理模块,提供了声明式和编程式事务管理的支持。

3、Spring的设计核心是什么?

IOC和AOP

👩‍💻面试官追问谈谈你对IOC和AOP的理解?

答案:

4、Spring中的bean的作用域有哪些?

  • singleton(单例模式):唯一bean实例,Spring中的bean默认都是单例的。

  • prototype(原型模式):每次请求都会创建一个新的bean实例。

  • request(请求作用域):每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。

  • session(会话作用域):每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP session内有效。

  • global-session(全局作用域):全局session作用域,仅仅在基于Portlet的Web应用中才有意义,Spring5中已经没有了。Portlet是能够生成语义代码(例如HTML)片段的小型Java Web插件。它们基于Portlet容器,可以像Servlet一样处理HTTP请求。但是与Servlet不同,每个Portlet都有不同的会话。

5、Spring中Bean的注入方式?

  • 构造函数注入(Constructor Injection)
    • 通过构造函数将依赖项传递给Bean,确保了当Bean实例化时,它的依赖项就已经被设置好。
    • 这种方式可以保证依赖项为非空,因为构造函数必须在对象创建时被调用。
  • setter方法注入(Setter Injection)
    • 通过调用Bean的setter方法来注入依赖项。
    • 这种方式提供了更大的灵活性,可以在Bean创建之后更改依赖关系。
  • 字段注入(Field Injection)
    • Spring可以直接注入Bean的字段,这种方式不需要编写构造函数或setter方法。
    • 字段注入较少使用,因为它违反了“封装”原则,使得字段可以被直接访问和修改。
  • 注解注入
    • Spring支持使用注解来简化配置,常见的注解包括@Autowired(用于构造函数、setter方法或字段)和@Inject(JSR-330标准)。
    • 注解注入可以与构造函数注入或setter方法注入结合使用。

除了以上方法,还有:使用@ComponentScan、@Bean、@Value、@Qualifier注解等等。用的最多的就是构造器注入、@autowired、@Bean、@Value。

6、BeanFactory 和 ApplicationContext有什么区别?

是spring的核心接口,都可以作为容器,ApplicationContext是BeanFactory的子接口。
BeanFactory: 是spring最底层的接口,包含各种Bean的定义和Bean的管理。
ApplicationContext: 作为BeanFactory的派生,除了有BeanFactory的功能以外,还提供了更多的功能。

区别:

  1. BeanFactroy采用的是延迟加载形式来注入Bean的,使用到bean才会加载。ApplicationContext一次性加载所有bean。
  2. BeanFactory需要手动注册,而ApplicationContext则是自动注册。
  3. BeanFactory不支持国际化,ApplicationContext支持国际化(实现MessageSource接口)。
  4. BeanFactory不支持AOP,ApplicationContext支持AOP,可以与Spring的AOP框架集成,提供声明式事务管理。

7、Spring中的单例bean的线程安全问题了解吗?

单例bean存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。

有两种常见的解决方案:

  1. 在bean对象中尽量避免定义可变的成员变量(不太现实)。
  2. 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中(推荐的一种方式)。

示例:

public class UserService {
    private String username;

    public String setUserName(String username){
        this.username = "User :" + username;

        //模拟业务代码
        try {
            Thread.sleep(500);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        return this.username;
    }
}
@Configuration
public class MainConfig {

    @Bean
    public UserService userService(){
        return new UserService();
    }
}
public class Client {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(MainConfig.class);
        applicationContext.refresh();

        UserService userService = applicationContext.getBean(UserService.class);

        //线程一
        new Thread(()->System.out.println(userService.setUserName("张三"))).start();
        //线程二
        new Thread(()-> System.out.println(userService.setUserName("李四"))).start();

    }
}


User :李四
User :李四

我们可以看到,打印出了一样的结果,说明不同线程对同一个Bean修改时会出现线程安全,我们修改userService代码将他变为线程安全

public class UserService {
//    private String username;
    //将username放入ThreadLocal里面
    ThreadLocal<String> username =ThreadLocal.withInitial(() -> "default");
    public String setUserName(String username){
        this.username.set("User :" + username);

        //模拟业务代码
        try {
            Thread.sleep(500);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        return this.username.get();
    }
}

User :李四
User :张三

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

除了上一题中给出的两种解决方法外,还有其他的解决方法,比如:

  1. 把成员变量写在方法内。
  2. 修改bean的作用域,singleton改为prototype。(@Scope(“prototype”))
  3. 使用synchronized修饰。

9、Spring中的bean生命周期?

  1. 实例化Bean:通过构造器或静态工厂方法创建Bean实例。

  2. 设置Bean属性:为Bean的属性设置值,这些属性可能是通过XML配置、注解或Java配置类指定的。

  3. 处理BeanNameAware和BeanFactoryAware

    • 如果Bean实现了BeanNameAware接口,Spring将调用其setBeanName()方法,传入Bean的ID。
    • 如果Bean实现了BeanFactoryAware接口,Spring将调用其setBeanFactory()方法,传入BeanFactory容器的实例。
  4. BeanPostProcessor前置处理:在Bean的初始化方法调用之前,Spring允许通过BeanPostProcessor接口的postProcessBeforeInitialization()方法对Bean进行额外处理。

  5. 初始化Bean

    • 如果Bean实现了InitializingBean接口,Spring将调用其afterPropertiesSet()方法。
    • 如果Bean在XML中配置了init-method属性,Spring将调用指定的初始化方法。
  6. BeanPostProcessor后置处理:在Bean初始化之后,Spring调用BeanPostProcessor接口的postProcessAfterInitialization()方法,允许对Bean进行进一步的处理。

  7. 使用Bean:此时Bean已经准备好被应用程序使用了,Spring容器将根据配置将Bean注入到其他需要的地方。

  8. 处理DisposableBean和destroy-method

    • 当容器关闭时,如果Bean实现了DisposableBean接口,Spring将调用其destroy()方法。
    • 如果Bean在XML中配置了destroy-method属性,Spring将调用指定的销毁方法。
  9. 销毁Bean:容器关闭时,Bean的实例将被销毁,释放资源。

10、Spring Bean的扩展点?

Spring提供很多的扩展点,这里就列举几个比较常用的。

  1. BeanFactoryPostProcessor:在BeanFactory初始化之后,容器中的所有Bean定义被加载,但实例化之前,可以修改BeanFactory中的Bean定义。

  2. BeanPostProcessor:在Bean的初始化过程中,可以在Bean属性设置好之后和初始化方法调用之前或之后,对Bean进行额外处理。

  3. BeanNameAware 和 BeanFactoryAware:这些是Aware接口,允许Bean获取自己的名称和BeanFactory的引用。

  4. InitializingBean 和 DisposableBean:这些是特殊的接口,可以在Bean初始化和销毁时提供自定义的逻辑。

  5. @PostConstruct 和 @PreDestroy:这两个注解分别用于标记在Bean初始化之后和销毁之前执行的方法。

  6. 自定义初始化和销毁方法:可以在Bean定义中指定初始化方法(init-method)和销毁方法(destroy-method)。

  7. ApplicationContextAwareEnvironmentAware:允许Bean获取Spring的ApplicationContext和外部配置的Environment,从而访问配置信息或上下文功能。

11、介绍下 Spring IOC 容器加载流程?

我们大致可以分为两个阶段:

  • IOC容器初始化阶段:根据程序里面定义XML、注解等Bean的声明方式,通过解析和加载后生成的BeanDefinition,然后把BeanDefinition存入到一个Map集合里面,完成IOC的初始化阶段。
  • 完成Bean的初始化和DI:通过反射对一个没有设置Lazy-init属性的单例Bean进行初始化,然后进行依赖注入,将属性注入到Bean对象中。

12、说说自己对于Spring MVC的了解?

简单流程如下所示:

 具体工作原理:

流程说明:

  1. 客户端(浏览器)发送请求,直接请求到DispatcherServlet
  2. DispatcherServlet根据请求信息调用HandlerMapping解析请求对应的Handler
  3. 解析到对应的Handler(也就是我们平常说的Controller控制器)。
  4. HandlerAdapter会根据Handler来调用真正的处理器来处理请求和执行相对应的业务逻辑。
  5. 处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象View逻辑上的View
  6. ViewResolver会根据逻辑View去查找实际的View
  7. DispatcherServlet把返回的Model传给View(视图渲染)。
  8. View返回给请求者(浏览器)。

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

  • 工厂设计模式:Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对象。
  • 代理设计模式:Spring AOP功能的实现。
  • 单例设计模式:Spring中的bean默认都是单例的。
  • 模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到了模板模式。
  • 包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
  • 观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。
  • 适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式、Spring MVC中也是用到了适配器模式适配Controller。

14、@Component和@Bean的区别是什么?

  1. 作用对象不同。@Component注解作用于,而@Bean注解作用于方法
  2. @Component注解通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用@ComponentScan注解定义要扫描的路径)。@Bean注解通常是在标有该注解的方法中定义产生这个bean,告诉Spring这是某个类的实例,当我需要用它的时候还给我。
  3. @Bean注解比@Component注解的自定义性更强,而且很多地方只能通过@Bean注解来注册bean。比如当引用第三方库的类需要装配到Spring容器的时候,就只能通过@Bean注解来实现。

15、Spring事务管理的方式有几种?

1.编程式事务:在代码中硬编码(不推荐使用)如:beginTransaction()、commit()、rollback()等。

2.声明式事务:在配置文件中配置(推荐使用),分为基于XML的声明式事务和基于注解的声明式事务。

16、Spring事务中的隔离级别有哪几种?

在TransactionDefinition接口中定义了五个表示隔离级别的常量:

  • ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。
  • ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
  • ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

17、Spring事务中有哪几种事务传播行为?

在TransactionDefinition接口中定义了7个表示事务传播行为的常量。

支持当前事务的情况:

  • PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)。
  • 不支持当前事务的情况:
  • PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
  • 其他情况:
  • PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED

  • 24
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring的底层原理主要包括以下几个方面:IOC(Inverse of Control,控制反转)、AOP(Aspect-Oriented Programming,面向切面编程)、Bean生命周期管理、以及Spring的核心组件。 1. IOC(控制反转):IOC是Spring的核心思想,它通过容器管理和维护对象之间的依赖关系,将对象的创建、组装和生命周期交给容器来管理。在Spring中,我们通过配置文件或者注解来描述对象之间的依赖关系,而不是在代码中直接去创建和关联对象。 2. AOP(面向切面编程):AOP是一种编程思想,它将应用程序的业务逻辑与横切关注点(如日志、事务、安全等)分离开来,实现了模块化的设计。Spring利用AOP可以实现诸如日志记录、性能统计、事务管理等横切关注点的功能。 3. Bean生命周期管理:Spring通过Bean生命周期管理来管理Bean的创建、初始化、使用和销毁等过程。在容器启动时,Spring会根据配置信息创建Bean实例并进行初始化,然后在需要使用时将Bean注入到其他对象中。当容器关闭时,Spring会销毁这些Bean实例。 4. Spring的核心组件:Spring的核心组件包括容器(ApplicationContext)、BeanFactory、BeanPostProcessor等。容器负责管理和维护Bean的生命周期,提供依赖注入和AOP的支持;BeanFactory是Spring的核心接口,定义了容器的基本功能;BeanPostProcessor是一个回调接口,可以在Bean实例化、初始化和销毁的过程中介入进行扩展。 总之,Spring底层原理主要围绕IOC、AOP和Bean生命周期管理展开,通过这些机制实现了松耦合、可维护和可扩展的应用程序开发。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小杰不秃头

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

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

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

打赏作者

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

抵扣说明:

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

余额充值