Spring核心面试题汇总

❃博主首页 : 「码到三十五」 ,同名公众号 :「码到三十五」,wx号 : 「liwu0213」
☠博主专栏 : <源码解读> <面试攻关>
♝博主的话 : 搬的每块砖,皆为峰峦之基;公众号搜索「码到三十五」关注这个爱发技术干货的coder,一起筑基

文章目录

      • 1. Spring容器是如何初始化Bean的?请详细描述Bean的生命周期。
      • 2. Spring中的AOP是如何实现的?请解释其底层原理。
      • 3. Spring中的事务管理是如何实现的?请解释其底层机制。
      • 4. Spring中的`ApplicationContext`与`BeanFactory`有何区别?请详细解释。
      • 5. 请解释Spring中的类型转换机制,并说明如何在Spring中进行自定义类型转换。
      • 6. Spring是如何实现依赖注入的?请解释其内部机制。
      • 7. Spring中的循环依赖是如何解决的?
      • 8. 解释一下Spring中的三级缓存机制,以及它在解决循环依赖中的作用。只有二级缓存可以解决循环依赖吗
        • 三级缓存解决循环依赖的作用
        • 是否只有二级缓存可以解决循环依赖?
      • 9. Spring中的事件机制是如何实现的?请解释其工作原理。
      • 10. 请解释Spring中的@Transactional注解的工作原理,并说明其事务传播行为。
      • 11. 请解释Spring中的@Async注解的工作原理,并说明其异步执行机制。
      • 12. **Spring MVC中的DispatcherServlet是如何工作的?**

1. Spring容器是如何初始化Bean的?请详细描述Bean的生命周期。

答案要点

  • 实例化:Spring容器通过调用Bean的构造器或工厂方法创建Bean实例。
  • 属性填充:Spring容器将Bean的属性(包括依赖注入的Bean)设置到Bean实例中。
  • BeanNameAware接口:如果Bean实现了此接口,Spring会调用其setBeanName方法,将Bean的名称传递给它。
  • BeanFactoryAware接口:如果Bean实现了此接口,Spring会调用其setBeanFactory方法,将BeanFactory实例传递给它。
  • ApplicationContextAware接口:如果Bean实现了此接口,并且Bean在ApplicationContext中定义,Spring会调用其setApplicationContext方法,将ApplicationContext实例传递给它。
  • BeanPostProcessor接口:在Bean初始化前后,Spring会调用实现了此接口的类的postProcessBeforeInitializationpostProcessAfterInitialization方法,允许对Bean进行额外的处理。
  • InitializingBean接口:如果Bean实现了此接口,Spring会在Bean初始化后调用其afterPropertiesSet方法。
  • init-method属性:在Bean的配置文件中,可以使用init-method属性指定一个初始化方法,Spring会在Bean初始化后调用此方法。
  • DisposableBean接口:如果Bean实现了此接口,当Spring容器关闭时,会调用其destroy方法,允许Bean在销毁前进行清理工作。
  • destroy-method属性:在Bean的配置文件中,可以使用destroy-method属性指定一个销毁方法,当Spring容器关闭时,会调用此方法。

2. Spring中的AOP是如何实现的?请解释其底层原理。

答案要点

  • **AOP(面向切面编程)**是一种编程范式,允许将横切关注点(如日志、事务管理等)与业务逻辑分离。
  • Spring AOP基于动态代理实现,对于实现了接口的Bean,使用JDK动态代理;对于没有实现接口的Bean,使用CGLIB代理。
  • 动态代理会在运行时创建代理对象,代理对象会拦截对目标方法的调用,并在调用前后执行额外的逻辑(即切面)。
  • Spring AOP使用Advisor(通知器)和Pointcut(切入点)来定义切面。Advisor包含了一个Advice(通知),它定义了要在目标方法调用前后执行的逻辑。Pointcut定义了哪些方法调用会被拦截。
  • Spring AOP还支持自定义Aspect(切面),允许将多个AdvicePointcut组合在一起。

3. Spring中的事务管理是如何实现的?请解释其底层机制。

答案要点

  • Spring支持声明式事务管理和编程式事务管理。声明式事务管理是通过注解或XML配置来实现的,而编程式事务管理是通过编程方式显式地开启、提交和回滚事务。
  • Spring事务管理的底层是基于AOP实现的。当使用声明式事务管理时,Spring会在运行时为被事务管理的方法创建代理对象,并在方法调用前后执行事务管理逻辑。
  • Spring事务管理支持多种事务管理器,如JDBC事务管理器、JPA事务管理器等。这些事务管理器实现了PlatformTransactionManager接口,提供了事务的开启、提交、回滚等操作。
  • Spring事务管理还提供了事务的传播行为、隔离级别、超时时间等配置选项,允许开发人员根据实际需求进行灵活配置。

4. Spring中的ApplicationContextBeanFactory有何区别?请详细解释。

答案要点

  • BeanFactory是Spring中最基本的容器接口,提供了配置框架和基本的功能,主要用于高级定制。它只能管理单例Bean,不支持注解、AOP等功能。
  • ApplicationContextBeanFactory的子接口,提供了更多企业级的功能,如事件传播、声明式服务等。它支持国际化、资源加载、注解处理、AOP等功能。
  • ApplicationContext在初始化时会进行预实例化,即创建并初始化所有的单例Bean;而BeanFactory则采用延迟初始化策略,只有在请求Bean时才会创建和初始化它。
  • ApplicationContext是Spring框架的推荐用法,因为它提供了更丰富的功能和更好的用户体验。

5. 请解释Spring中的类型转换机制,并说明如何在Spring中进行自定义类型转换。

答案要点

  • Spring中的类型转换机制是通过PropertyEditorConverter接口来实现的。PropertyEditor用于将字符串转换为其他类型的对象,而Converter则提供了更通用的类型转换方法。
  • 在Spring 3.0之后,推荐使用Converter接口进行类型转换,因为它提供了更灵活和强大的类型转换能力。
  • 要在Spring中进行自定义类型转换,可以创建实现Converter接口的类,并在配置文件中将其注册为Spring容器中的Bean。然后,在需要转换类型的地方,Spring会自动使用注册的转换器进行转换。

当然,以下是一些额外的、有深度的Spring框架面试题,这些题目进一步探讨了Spring的核心概念、源码实现以及高级特性:

6. Spring是如何实现依赖注入的?请解释其内部机制。

答案要点

  • 依赖注入(DI)是Spring框架的核心功能之一,它允许对象在创建时不直接依赖其他对象,而是在运行时由外部容器(即Spring容器)注入依赖。
  • Spring通过反射机制和Java的接口与实现类之间的解耦来实现依赖注入。当Spring容器启动时,它会读取配置文件或注解,获取Bean的定义和依赖关系。
  • Spring容器会按照配置的顺序创建Bean实例,并根据依赖关系将Bean注入到其他Bean中。对于依赖注入,Spring支持构造器注入、Setter注入和接口注入等方式。
  • 在Spring的源码中,BeanFactory接口是依赖注入的核心接口,它定义了获取Bean的方法。而ApplicationContext接口则扩展了BeanFactory,提供了更多企业级的功能,如事件发布、资源加载等。

7. Spring中的循环依赖是如何解决的?

答案要点

  • 循环依赖是指两个或多个Bean相互依赖,形成一个闭环。在Spring中,循环依赖通常发生在单例Bean之间。
  • Spring通过三级缓存(一级缓存为singletonObjects,二级缓存为earlySingletonObjects,三级缓存为singletonFactories)来解决单例Bean之间的循环依赖问题。
  • 当Spring容器创建Bean时,会先将Bean的工厂对象放入三级缓存中,然后在创建过程中,如果检测到循环依赖,会从三级缓存中获取工厂对象,并调用其getObject方法来创建Bean实例,然后将Bean实例放入二级缓存中。最后,当Bean创建完成后,会从二级缓存中取出Bean实例,放入一级缓存中。

在Spring框架中,三级缓存机制是处理单例Bean创建和依赖注入过程中的一种重要策略,特别是在解决循环依赖问题上发挥着关键作用。以下是对Spring三级缓存机制的详细解释,以及关于是否只有二级缓存可以解决循环依赖的探讨。

8. 解释一下Spring中的三级缓存机制,以及它在解决循环依赖中的作用。只有二级缓存可以解决循环依赖吗

  1. 一级缓存(singletonObjects)

    • 这是一个存储完全初始化后的Bean实例的缓存。
    • 当通过getBean方法请求一个Bean时,Spring会首先在这个缓存中查找。如果找到,则直接返回该Bean实例,避免重复创建。
  2. 二级缓存(earlySingletonObjects)

    • 这个缓存用于存储早期曝光的Bean实例,这些实例尚未完全初始化。
    • 在Bean的创建过程中,如果遇到循环依赖,Spring会从这个缓存中提供一个早期引用,以允许Bean之间的依赖注入。
  3. 三级缓存(singletonFactories)

    • 这个缓存存储的是可以生成Bean实例的工厂对象(ObjectFactory)。
    • 当Spring第一次创建Bean时,如果一级和二级缓存中都没有该Bean的实例,它会从三级缓存中获取工厂对象,通过该对象创建Bean实例,并将其放入二级缓存中(如果适用),最终放入一级缓存中。
三级缓存解决循环依赖的作用

循环依赖是指两个或多个Bean相互依赖,导致它们无法独立地完成初始化。在没有三级缓存机制的情况下,Spring可能会陷入死锁或抛出异常,因为每个Bean都在等待另一个Bean完成初始化。

三级缓存机制通过以下方式解决循环依赖:

  • 当Spring创建一个Bean(例如Bean A)时,它会将A的工厂对象放入三级缓存中。
  • 如果在A的创建过程中,A需要依赖另一个Bean(例如Bean B),而B又依赖于A(形成循环依赖),则Spring会尝试从缓存中获取A的实例。
  • 由于A尚未完全初始化,Spring会从三级缓存中获取A的工厂对象,通过它创建一个早期的、未完全初始化的A实例,并将其放入二级缓存中。
  • 然后,Spring可以继续创建B的实例,并将B放入相应的缓存中(可能是完全初始化后放入一级缓存,也可能是作为早期引用放入二级缓存)。
  • 一旦B创建完成,Spring可以回到A的创建过程,完成A的剩余初始化工作,并将最终初始化的A实例放入一级缓存中。

通过这种方式,Spring能够在不陷入死锁的情况下解决循环依赖问题,同时确保每个Bean都能够获得其所需的依赖。

是否只有二级缓存可以解决循环依赖?

答案是否定的。虽然二级缓存确实在解决循环依赖中起到了关键作用,但仅有二级缓存是不够的。原因如下:

  • 二级缓存只能存储已经创建出的对象引用,但某些代理对象需要延迟创建。如果放弃使用三级缓存,即没有ObjectFactory,那么就需要将早期的Bean放入二级缓存。但问题是,应该将未被代理的Bean还是代理的Bean放入二级缓存,这只能在属性注入阶段,处理注解时才能分辨。
  • 如果没有三级缓存来存储工厂对象,Spring就无法在Bean创建的中途暂停,去处理依赖的另一个Bean。这会导致循环依赖问题无法解决,因为每个Bean都在等待另一个Bean完成初始化。

因此,三级缓存机制是Spring解决循环依赖问题的一个完整方案,而不仅仅是二级缓存。

9. Spring中的事件机制是如何实现的?请解释其工作原理。

答案要点

  • Spring的事件机制允许应用程序在运行时发布和监听事件。这提供了一种解耦的通信方式,使得组件之间可以在不直接依赖对方的情况下进行交互。
  • 在Spring中,事件通常是通过实现ApplicationEvent接口或扩展其子类来定义的。发布事件则是通过ApplicationEventPublisher接口或ApplicationContext接口来实现的。
  • 当事件被发布时,Spring会查找所有注册了对应事件监听器的Bean,并调用它们的onApplicationEvent方法来处理事件。这些监听器通常是通过实现ApplicationListener接口来定义的。
  • Spring的事件机制还支持事件传播机制,即事件可以在不同的上下文(如父子ApplicationContext)之间传播。这使得事件可以在更广泛的范围内被处理和响应。

10. 请解释Spring中的@Transactional注解的工作原理,并说明其事务传播行为。

答案要点

  • @Transactional注解是Spring框架提供的一个声明式事务管理注解,它允许开发人员在不编写事务管理代码的情况下,通过简单的注解配置来实现事务管理。
  • 当在方法上使用@Transactional注解时,Spring会在运行时为该方法创建代理对象,并在方法调用前后执行事务管理逻辑。这包括开启事务、提交事务和回滚事务等操作。
  • @Transactional注解还支持多种事务传播行为,如REQUIRED(如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务)、REQUIRES_NEW(创建一个新的事务,并暂停当前事务(如果存在))等。这些传播行为允许开发人员根据实际需求来配置事务的行为。
  • 在Spring的源码中,@Transactional注解是通过AOP(面向切面编程)技术来实现的。当Spring容器启动时,它会扫描所有的Bean,并查找带有@Transactional注解的方法。然后,Spring会为这些方法创建代理对象,并在方法调用时执行事务管理逻辑。

11. 请解释Spring中的@Async注解的工作原理,并说明其异步执行机制。

答案要点

  • @Async注解是Spring框架提供的一个用于声明异步方法的注解。当在方法上使用@Async注解时,Spring会在运行时将该方法调用放入一个单独的线程中执行,从而实现异步执行。
  • 要使用@Async注解,首先需要在配置类中启用异步支持,通常是通过在配置类上添加@EnableAsync注解来实现的。
  • 当调用带有@Async注解的方法时,Spring会创建一个新的线程来执行该方法。这个新线程是由Spring的TaskExecutor(任务执行器)来管理的。TaskExecutor是一个接口,它定义了提交任务和执行任务的方法。在Spring中,可以使用不同的TaskExecutor实现来配置异步任务的执行方式。
  • 通过@Async注解和TaskExecutor的配合使用,Spring提供了一种简单而有效的异步执行机制,使得开发人员可以轻松地实现异步任务的处理和响应。

12. Spring MVC中的DispatcherServlet是如何工作的?

DispatcherServlet是Spring MVC中的前端控制器,它负责接收HTTP请求并将其分发到相应的处理器(Controller)。工作流程大致如下:

  1. 请求接收:DispatcherServlet接收客户端发送的HTTP请求。
  2. 处理器映射:DispatcherServlet根据请求的URL和请求参数等信息,通过HandlerMapping找到对应的处理器(Controller)。
  3. 处理器执行:DispatcherServlet调用找到的处理器来执行请求。处理器可以是一个简单的POJO,也可以是一个更复杂的组件。
  4. 视图解析:处理器执行完成后,返回一个ModelAndView对象,其中包含了要渲染的视图名和数据模型。DispatcherServlet通过ViewResolver解析视图名,找到对应的视图技术(如JSP、Thymeleaf等)。
  5. 视图渲染:DispatcherServlet将解析后的视图和数据模型传递给视图技术进行渲染,最终生成HTML响应发送给客户端。

关注公众号[码到三十五]获取更多技术干货 !

你可能感兴趣的:(Spring全家桶,面试攻关,spring,spring,boot,spring,cloud,微服务,数据挖掘)