Spring经典高频面试题,原来是长这个样子

本文深入探讨Spring框架的基本概念,包括其主要模块、优势、控制反转与依赖注入原理,以及BeanFactory和ApplicationContext的区别。同时,详细介绍了Spring的配置方式,包括XML、注解和Java配置,展示了如何在Spring中使用依赖注入。

640?wx_fmt=gif

本文选自《Spring 5核心原理与30个类手写实战》一书,本文题目目录:

1  什么是Spring框架,Spring框架有哪些主要模块

2  使用Spring框架能带来哪些好处

3  什么是控制反转(IoC),什么是依赖注入

4  在Java中依赖注入有哪些方式

5  BeanFactory和ApplicationContext有什么区别

6  Spring提供几种配置方式来设置元数据

7  如何使用XML配置方式配置Spring

8  Spring提供哪些配置形式

9  怎样用注解的方式配置Spring

10  请解释Spring Bean的生命周期

11  更多经典高频面试题

01

什么是Spring框架,Spring框架有哪些主要模块

Spring框架是一个为Java应用程序开发提供综合、广泛的基础性支持的Java平台。Spring帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。Spring框架本身也是按照设计模式精心打造的,这使得我们可以在开发环境中安心地集成Spring框架,不必担心Spring是如何在后台工作的。

02

使用Spring框架能带来哪些好处

下面列举了一些使用Spring框架带来的主要好处。

(1)Dependency Injection(DI)使得构造器和JavaBean properties文件中的依赖关系一目了然。

(2)与EJB容器相比较,IoC容器更加趋向于轻量级。这样一来使用IoC容器在有限的内存和CPU资源的情况下进行应用程序的开发和发布就变得十分有利。

(3)Spring并没有闭门造车,Spring利用了已有的技术,比如ORM框架、logging框架、J2EE、Quartz和JDK Timer,以及其他视图技术。

(4)Spring框架是按照模块的形式来组织的。由包和类的编号就可以看出其所属的模块,开发者只需选用需要的模块即可。

(5)要测试一个用Spring开发的应用程序十分简单,因为测试相关的环境代码都已经囊括在框架中了。更加简单的是,利用JavaBean形式的POJO类,可以很方便地利用依赖注入来写入测试数据。

(6)Spring的Web框架也是一个精心设计的Web MVC框架,为开发者在Web框架的选择上提供了一个除主流框架(比如Struts)和过度设计的、不流行Web框架以外的选择。

(7)Spring提供了一个便捷的事务管理接口,适用于小型的本地事务处理(比如在单DB的环境下)和复杂的共同事务处理(比如利用JTA的复杂DB环境)。

03

什么是控制反转(IoC),什么是依赖注入

(1)控制反转是应用于软件工程领域的,在运行时被装配器对象用来绑定耦合对象的一种编程技巧,对象之间的耦合关系在编译时通常是未知的。在传统的编程方式中,业务逻辑的流程是由应用程序中早已被设定好关联关系的对象来决定的。在使用控制反转的情况下,业务逻辑的流程是由对象关系图来决定的,该对象关系图由装配器负责实例化,这种实现方式还可以将对象之间的关联关系的定义抽象化。绑定的过程是通过“依赖注入”实现的。

(2)控制反转是一种以给予应用程序中目标组件更多控制为目的设计范式,并在实际工作中起到了有效的作用。

(3)依赖注入是在编译阶段尚未知所需的功能是来自哪个的类的情况下,将其他对象所依赖的功能对象实例化的模式。这就需要一种机制来激活相应的组件以提供特定的功能,所以依赖注入是控制反转的基础。否则如果在组件不受框架控制的情况下,框架又怎么知道要创建哪个组件呢?

04

在Java中依赖注入有哪些方式

(1)构造器注入。

(2)Setter方法注入。

(3)接口注入。

05

 BeanFactory和ApplicationContext有什么区别

BeanFactory 可以理解为含有Bean集合的工厂类。BeanFactory 包含了Bean的定义,以便在接收到客户端请求时将对应的Bean实例化。

BeanFactory还能在实例化对象时生成协作类之间的关系。此举将Bean自身从Bean客户端的配置中解放出来。BeanFactory还包含Bean生命周期的控制,调用客户端的初始化方法(Initialization Method)和销毁方法(Destruction Method)。

从表面上看,ApplicationContext如同BeanFactory一样具有Bean定义、Bean关联关系的设置及根据请求分发Bean的功能。但ApplicationContext在此基础上还提供了其他功能。

(1)提供了支持国际化的文本消息。

(2)统一的资源文件读取方式。

(3)已在监听器中注册的Bean的事件。

以下是三种较常见的 ApplicationContext 实现方式。

(1) ClassPathXmlApplicationContext: 从ClassPath的XML配置文件中读取上下文,并生成上下文定义。应用程序上下文从程序环境变量中取得。 

ApplicationContext context = new ClassPathXmlApplicationContext(“application.xml”);
(2)FileSystemXmlApplicationContext :由文件系统中的XML配置文件读取上下文。 
ApplicationContext context = new FileSystemXmlApplicationContext(“application.xml”);
(3)XmlWebApplicationContext:由Web应用的XML文件读取上下文。

06

Spring提供几种配置方式来设置元数据

Spring提供以下三种配置方式来设置元数据:
(1)基于XML的配置。
(2)基于注解的配置。
(3)基于Java的配置。

07

如何使用XML配置方式配置Spring

在Spring框架中,依赖和服务需要专门的配置文件实现,一般用XML格式的配置文件。这些配置文件的格式采用公共的模板,由一系列的Bean定义和专门的应用配置选项组成。 
Spring XML配置的主要目的是使所有的Spring组件都可以用XML文件的形式来进行配置。这意味着不会出现其他的Spring配置类型(比如声明配置方式或基于Java Class的配置方式)。
Spring的XML配置方式是使用被Spring命名空间所支持的一系列的XML标签来实现的。Spring主要的命名空间有context、beans、jdbc、tx、aop、mvc和aso。例如:
<beans>	
   <!-- JSON Support -->	
   <bean name="viewResolver"	
        class="org.springframework.web.servlet.view.BeanNameViewResolver"/>	
   <bean name="jsonTemplate"	
        class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>	
   <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>	
</beans>
下面这个web.xml仅配置了DispatcherServlet,最简单的配置便能满足应用程序配置运行时组件的需求。
<web-app>	
   <display-name>Archetype Created Web Application</display-name>	
   <servlet>	
      <servlet-name>spring</servlet-name>	
      <servlet-class>	
         org.springframework.web.servlet.DispatcherServlet	
      </servlet-class>	
      <load-on-startup>1</load-on-startup>	
   </servlet>	
   <servlet-mapping>	
      <servlet-name>spring</servlet-name>	
      <url-pattern>/</url-pattern>	
   </servlet-mapping>	
</web-app>

08

Spring提供哪些配置形式

Spring对Java配置的支持是由@Configuration注解和@Bean注解来实现的。由@Bean注解的方法将会实例化、配置和初始化一个新对象,这个对象将由Spring的IoC容器来管理。@Bean声明所起到的作用与元素类似。被@Configuration所注解的类则表示这个类的主要目的是作为Bean定义的资源。被@Configuration声明的类可以通过在同一个类内部调用@bean方法来设置嵌入Bean的依赖关系。

最简单的@Configuration 声明类请参考下面的代码:

@Configuration	
public class AppConfig{	
   @Bean	
   public MyService myService() {	
      return new MyServiceImpl();	
   }	
}

与上面的@Beans配置文件相同的XML配置文件如下:

<beans>	
   <bean id="myService" class="com.gupaoedu.services.MyServiceImpl"/>	
</beans>

上述配置方式的实例化方式如下:

public static void main(String[] args) {	
   ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);	
   MyService myService = ctx.getBean(MyService.class);	
   myService.doStuff();	
}

要使用组件扫描,仅需用@Configuration进行注解即可:

@Configuration	
@ComponentScan(basePackages = "com.gupaoedu")	
public class AppConfig  {	
}
在上面的例子中,com.gupaoedu包首先会被扫描到,然后在容器内查找被@Component 声明的类,找到后将这些类按照Spring Bean定义进行注册。 
如果你要在Web应用开发中选用上述配置方式,需要用AnnotationConfigWebApplicationContext类来读取配置文件,可以用来配置Spring的Servlet监听器ContrextLoaderListener或者Spring MVC的DispatcherServlet。
例如:
<web-app>	
   <context-param>	
      <param-name>contextClass</param-name>	
      <param-value>	
         org.springframework.web.context.support.AnnotationConfigWebApplicationContext	
      </param-value>	
   </context-param>	
   <context-param>	
      <param-name>contextConfigLocation</param-name>	
      <param-value>com.gupaoedu.AppConfig</param-value>	
   </context-param>	
   <listener>	
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>	
   </listener>	
   <servlet>	
      <servlet-name>dispatcher</servlet-name>	
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>	
      <init-param>	
         <param-name>contextClass</param-name>	
         <param-value>	
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext	
         </param-value>	
      </init-param>	
      <init-param>	
         <param-name>contextConfigLocation</param-name>	
         <param-value>com.gupaoedu.web.MVCConfig</param-value>	
      </init-param>	
   </servlet>	
   <servlet-mapping>	
      <servlet-name>dispatcher</servlet-name>	
      <url-pattern>/web/*</url-pattern>	
   </servlet-mapping>	
</web-app>

09

怎样用注解的方式配置Spring

Spring在2.5版本以后开始支持用注解的方式配置依赖注入。可以用注解的方式来替代XML方式的Bean描述,可以将Bean描述转移到组件类的内部,只需要在相关类上、方法上或者字段声明上使用注解即可。注解注入将会被容器在XML注入之前处理,所以后者会覆盖前者对于同一个属性的处理结果。
注解装配在Spring中是默认关闭的,需要在Spring文件中进行配置才能使用基于注解的装配模式。如果你想要在应用程序中使用注解的方式,请参考如下配置:
<beans>	
   <context:annotation-config/>	
</beans>
配置完成以后,就可以用注解的方式在Spring中向属性、方法和构造方法中自动装配变量。
下面是几种比较重要的注解类型。
(1)@Required:该注解应用于设值方法。 
(2)@Autowired:该注解应用于设值方法、非设值方法、构造方法和变量。 
(3)@Qualifier:该注解和@Autowired注解搭配使用,用于消除特定Bean自动装配的歧义。 
(4)JSR-250 Annotations:Spring支持基于JSR-250 注解的注解,即@Resource、@PostConstruct和@PreDestroy。

10

请解释Spring Bean的生命周期

Spring Bean的生命周期简单易懂。在一个Bean实例被初始化时,需要执行一系列初始化操作以使其达到可用的状态。同样,当一个Bean不再被调用时需要进行相关的析构操作,并从Bean容器中移除。
Spring Bean Factory 负责管理在Spring容器中被创建的Bean的生命周期。Bean的生命周期由两组回调方法组成。 
(1)初始化之后调用的回调方法。 
(2)销毁之前调用的回调方法。 
Spring提供了以下4种方式来管理Bean的生命周期事件:
(1)InitializingBean和DisposableBean回调接口。
(2)针对特殊行为的其他Aware接口。
(3)Bean配置文件中的 customInit() 方法和 customDestroy() 方法。
(4)@PostConstruct和@PreDestroy注解方式。
使用customInit()和 customDestroy()方法管理Bean生命周期的代码样例如下:
<beans>	
   <bean id="demoBean" class="com.gupaoedu.task.DemoBean"	
        init-Method="customInit" destroy-Method="customDestroy">	
   </bean>	
</beans>
更多经典高频面试题

11  Spring Bean作用域的区别是什么

12  什么是Spring Inner Bean

13  Spring中的单例Bean是线程安全的吗

14  请举例说明如何在Spring中注入一个Java集合

15  如何向Spring Bean中注入java.util.Properties

16  请解释Spring Bean的自动装配

17  自动装配有哪些局限性

18  请解释各种自动装配模式的区别

19  请举例解释@Required注解

20  请举例说明@Qualifier注解

21  构造方法注入和设值注入有什么区别

22  Spring中有哪些不同类型的事件

23  FileSystemResource和ClassPathResource有什么区别

24  Spring中用到了哪些设计模式

25  在Spring中如何更有效地使用JDBC

26  请解释Spring中的IoC容器

27  在Spring中可以注入null或空字符串吗

题目详解请见《Spring 5核心原理与30个类手写实战》一书。

《Spring 5核心原理与30个类手写实战》一书基于编程开发实践,不仅深度解析Spring 5的原理与新特性,更从环境准备、顶层结构设计、数据访问等方面一步步地推导出Spring的设计原理。 在每个知识点上,均以大量的经典代码案例辅助讲解,使理论紧密联系实际。最后手写30个类,以体会Spring作者的创作过程,让每一位读者学以致用。

640?wx_fmt=jpeg

(点击封面了解本书详情)

640?wx_fmt=jpeg

640?wx_fmt=gif

作为码书商店的运营人员,诚邀你们进入我们的“优快云码书福利群”,进入群后,你想要的书籍都有推荐,你想要的优惠也都可以实现(当然不能让我卖掉我自己),你也可以在学习累的时候和大家吹吹牛放松放松

640?wx_fmt=png

640?wx_fmt=gif

### Spring Cloud 常见面试题及解答 #### 1. Spring Cloud 是什么? Spring Cloud 是一套基于 Spring Boot 实现的云应用开发工具集,它提供了一系列组件来解决分布式系统中的常见问题,例如服务注册与发现、配置管理、服务通信、负载均衡、断路器、网关等。Spring Cloud 的目标是简化微服务架构的开发和部署,使开发者能够更专注于业务逻辑的实现,而不是基础设施的复杂性。 #### 2. Spring Cloud 的主要组件有哪些?分别解释它们的作用 - **Eureka(服务注册与发现)**:Eureka 是 Netflix 提供的服务注册与发现组件,服务启动后会向 Eureka 注册自身信息(如 IP 地址、端口等),其他服务可以通过 Eureka 查找并调用已注册的服务。 - **Ribbon(客户端负载均衡)**:Ribbon 是一个客户端负载均衡器,它可以根据不同的策略(如轮询、随机等)将请求分发到多个服务实例上,从而提高系统的可用性和伸缩性。 - **Feign(声明式 REST 客户端)**:Feign 是一个声明式的 REST 客户端,它简化了服务间的 HTTP 通信,开发者只需定义接口即可完成服务调用。 - **Hystrix(断路器)**:Hystrix 是一个容错管理组件,它通过断路机制来防止服务雪崩。当某个服务调用失败或超时时,Hystrix 会自动切换到降级逻辑,避免整个系统崩溃。 - **Zuul(API 网关)**:Zuul 是 Netflix 提供的 API 网关组件,它负责路由请求、过滤、限流、认证等功能,是外部请求进入系统的统一入口。 - **Config(分布式配置中心)**:Spring Cloud Config 提供了集中化的配置管理功能,支持从 Git 或 SVN 等版本控制系统中获取配置信息,方便在不同环境中动态调整配置。 - **Sleuth(分布式链路追踪)**:Spring Cloud Sleuth 用于追踪微服务之间的调用链,帮助开发者分析请求在系统中的流转路径,便于排查问题。 - **Zipkin(分布式链路追踪)**:Zipkin 是一个分布式链路追踪系统,它可以与 Sleuth 集成,提供可视化的调用链分析界面。 #### 3. Spring Cloud Stream 是什么?它在微服务架构中的作用是什么? Spring Cloud Stream 是一个用于构建消息驱动的微服务应用的框架,它基于 Spring Boot 和 Spring Integration,简化了与消息中间件(如 Kafka、RabbitMQ)的集成。Spring Cloud Stream 提供了一种统一的编程模型,使得开发者可以轻松地编写生产者和消费者代码,并通过绑定器(Binder)抽象出底层的消息系统差异。它在微服务架构中的作用主要包括: - 实现服务间的异步通信,提升系统的解耦能力; - 支持多种消息中间件,增强系统的灵活性; - 提供持久化消息处理、消息分区、错误处理等功能,增强系统的可靠性和可扩展性。 #### 4. Spring Cloud Stream 的编程模型特点是什么?它如何简化消息处理? Spring Cloud Stream 的编程模型主要基于函数式编程风格,支持使用 `Supplier`、`Consumer` 和 `Function` 等函数式接口来定义消息的生产者和消费者。这种模型简化了消息处理的代码编写,开发者只需关注业务逻辑,而无需关心底层的消息传输细节。此外,Spring Cloud Stream 还支持通过注解(如 `@EnableBinding`)来定义消息通道,进一步降低了开发复杂度。 #### 5. Spring Cloud Stream 中的绑定器(Binder)是什么?常见的绑定器有哪些? 绑定器(Binder)是 Spring Cloud Stream 中的一个核心概念,它负责将消息通道(Channel)与具体的消息中间件(如 Kafka、RabbitMQ)进行绑定。绑定器抽象了底层消息系统的实现细节,使得开发者可以使用统一的 API 来操作不同的消息中间件。常见的绑定器包括: - `spring-cloud-stream-binder-kafka`:用于与 Apache Kafka 集成; - `spring-cloud-stream-binder-rabbit`:用于与 RabbitMQ 集成; - `spring-cloud-stream-binder-redis`:用于与 Redis 消息队列集成。 #### 6. 消息通道(Channel)在 Spring Cloud Stream 中的作用是什么?请给出一个配置示例。 消息通道(Channel)是 Spring Cloud Stream 中用于传输消息的核心抽象,它定义了消息的输入和输出方向。开发者可以通过定义 `Source`、`Sink` 和 `Processor` 接口来声明消息通道,并通过配置文件(如 `application.yml`)指定绑定器和消息中间件的相关参数。以下是一个简单的配置示例: ```yaml spring: cloud: stream: bindings: output: destination: my-topic binder: rabbit ``` 在这个示例中,`output` 是一个输出通道,消息将被发送到名为 `my-topic` 的 Kafka 主题或 RabbitMQ 队列中,具体取决于绑定器的类型。 #### 7. 如何在 Spring Cloud Stream 中配置持久性消息? 在 Spring Cloud Stream 中,持久性消息的配置通常依赖于所使用的绑定器。以 RabbitMQ 为例,可以通过以下配置启用持久化消息: ```yaml spring: cloud: stream: rabbit: bindings: output: producer: durable: true ``` 该配置确保消息在 RabbitMQ 中被持久化存储,即使在消费者暂时不可用的情况下也不会丢失。 #### 8. 什么是消息分区?在 Spring Cloud Stream 中如何实现? 消息分区是指将消息按照某种规则分发到不同的消费者实例上,以确保同一类消息总是被同一个消费者处理。在 Spring Cloud Stream 中,可以通过配置 `partitionKeyExpression` 和 `partitionCount` 来实现消息分区。例如: ```yaml spring: cloud: stream: bindings: input: consumer: partitioned: true instanceCount: 3 instanceIndex: 0 ``` 该配置表示有 3 个消费者实例,并且每个实例只处理属于自己的分区消息。 #### 9. Spring Cloud Stream 如何处理消息消费过程中的错误? Spring Cloud Stream 提供了多种错误处理机制,包括: - **重试机制**:可以通过配置 `maxAttempts` 和 `backOffInitialInterval` 来设置消息消费失败后的重试次数和间隔时间; - **死信队列(DLQ)**:当消息多次消费失败后,可以将其发送到死信队列,以便后续人工处理; - **自定义错误处理器**:开发者可以通过实现 `MessageHandler` 接口来自定义错误处理逻辑。 #### 10. 消息序列化和反序列化在 Spring Cloud Stream 中是如何工作的?可以自定义吗? Spring Cloud Stream 默认使用 `SimpleMessageConverter` 来处理消息的序列化和反序列化,支持 JSON、文本等多种格式。开发者可以通过自定义 `MessageConverter` 来实现特定的序列化和反序列化逻辑。例如: ```java @Bean public MessageConverter customMessageConverter() { return new MyCustomMessageConverter(); } ``` 通过这种方式,开发者可以根据业务需求灵活地控制消息的格式转换过程。 #### 11. 如何在 Spring Cloud Stream 中实现动态消息路由? 动态消息路由可以通过使用 `Router` 组件来实现。开发者可以定义一个 `Router` 函数,根据消息的内容动态决定消息应该被发送到哪个通道。例如: ```java @Bean public Function<Message<?>, String> router() { return message -> { // 根据消息内容决定路由目标 if (message.getPayload() instanceof String) { return "stringChannel"; } else { return "defaultChannel"; } }; } ``` #### 12. 如何在 Spring Cloud Stream 中使用多种数据源或触发器? Spring Cloud Stream 支持多数据源或多触发器的场景,开发者可以通过定义多个绑定器来连接不同的消息中间件。例如,可以同时使用 Kafka 和 RabbitMQ 作为消息传输的载体,并通过配置文件指定每个通道使用的绑定器。 #### 13. 如何测试 Spring Cloud Stream 应用? 测试 Spring Cloud Stream 应用可以通过以下方式进行: - **单元测试**:使用 `@SpringBootTest` 注解加载完整的 Spring 上下文,并模拟消息的生产和消费; - **集成测试**:使用嵌入式的消息中间件(如 Kafka 嵌入式服务器)来模拟真实的消息传输环境; - **Mockito 模拟**:使用 Mockito 模拟消息通道的行为,验证消息是否正确地被处理。 #### 14. Spring Cloud Stream 与 Spring Integration 有什么关系和区别? Spring Cloud Stream 是基于 Spring Integration 构建的,它继承了 Spring Integration 的许多特性,如消息通道、消息处理器等。两者的区别在于: - **Spring Integration**:主要用于构建企业级集成应用,支持点对点、发布/订阅等多种消息模式,适用于传统的单体应用; - **Spring Cloud Stream**:专注于微服务架构下的消息驱动应用开发,提供了更高层次的抽象和更简洁的编程模型,适合云原生环境。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值