五、spring bean 支持哪几种作用域?
Spring Bean 支持以下几种作用域:
-
singleton(单例):
- 这是默认的作用域。在整个 Spring IoC 容器中,对于一个给定的 Bean,只会创建一个实例。
- 无论有多少个地方请求这个 Bean,始终返回同一个实例。
- 优点是减少了对象创建的开销,适用于无状态的对象,例如服务类、工具类等。
-
prototype(原型):
- 每次请求这个 Bean 时,Spring 容器都会创建一个新的实例。
- 适用于有状态的对象,例如用户会话对象等。
- 缺点是每次请求都要创建新的对象,可能会带来一定的性能开销。
-
request(请求):
- 在 Web 应用中,在一次 HTTP 请求中,容器会创建一个新的 Bean 实例,并在请求结束时销毁它。
- 适用于存储与特定请求相关的数据,例如请求范围内的临时数据。
-
session(会话):
- 在 Web 应用中,在一个用户会话期间,容器会创建一个新的 Bean 实例,并在会话结束时销毁它。
- 适用于存储与用户会话相关的数据,例如用户的登录信息等。
-
application(应用):
- 在整个应用程序的生命周期中,只有一个 Bean 实例。
- 类似于 singleton,但作用域是整个应用程序而不是单个 Spring IoC 容器。
六、Spring bean 的生命周期是怎样的?
Spring Bean 的生命周期可以分为以下几个主要阶段:
一、实例化阶段
-
对象创建:
- 当 Spring 容器启动时,根据配置文件或注解扫描到需要创建的 Bean。
- 通过反射机制创建 Bean 的实例。例如,如果一个类有默认构造函数,Spring 会使用这个构造函数来创建对象。
-
依赖注入:
- 在对象创建后,Spring 会自动将 Bean 所依赖的其他 Bean 注入到当前 Bean 中。
- 这可以通过构造函数注入、Setter 方法注入或字段注入等方式实现。
二、初始化阶段
-
实现 InitializingBean 接口或配置 init-method:
- 如果 Bean 实现了
InitializingBean接口,Spring 会调用其afterPropertiesSet()方法进行初始化操作。 - 或者,可以在 Bean 的配置中指定一个
init-method方法,Spring 会在 Bean 属性设置完成后调用这个方法进行初始化。 - 初始化操作可以包括打开数据库连接、加载配置文件、初始化缓存等。
- 如果 Bean 实现了
-
BeanPostProcessor 处理:
- Spring 容器中的
BeanPostProcessor接口的实现类可以在 Bean 的初始化前后进行额外的处理。 BeanPostProcessor的postProcessBeforeInitialization()方法在初始化方法之前被调用,postProcessAfterInitialization()方法在初始化方法之后被调用。
- Spring 容器中的
三、使用阶段
- 业务方法调用:
- 在 Bean 初始化完成后,它可以被其他 Bean 或应用程序代码调用其业务方法。
- 例如,一个服务类的方法可以被控制器调用以处理业务逻辑。
四、销毁阶段
- 实现 DisposableBean 接口或配置 destroy-method:
- 当 Spring 容器关闭时,会触发 Bean 的销毁过程。
- 如果 Bean 实现了
DisposableBean接口,Spring 会调用其destroy()方法进行销毁操作。 - 或者,可以在 Bean 的配置中指定一个
destroy-method方法,Spring 会在容器关闭时调用这个方法进行销毁。 - 销毁操作可以包括关闭数据库连接、释放资源、清理缓存等。
七、Spring boot 有哪些优缺点?
Spring Boot 的优点:
- 快速开发:
- 极大地简化了 Spring 应用的开发过程,通过自动配置和起步依赖,开发者无需花费大量时间进行繁琐的配置。
- 可以快速搭建项目框架,专注于业务逻辑的实现。
- 微服务友好:
- 非常适合构建微服务架构,轻松实现服务的独立部署和扩展。
- 提供了与各种微服务相关的技术集成,如服务注册与发现(Eureka、Consul 等)、负载均衡(Ribbon)等。
- 内置服务器:
- 内嵌了 Tomcat、Jetty 等服务器,无需单独部署应用服务器,方便开发和测试。
- 可以快速启动项目进行本地调试。
- 强大的生态系统:
- 基于 Spring 框架,拥有庞大的社区和丰富的第三方库支持。
- 可以方便地集成各种数据库、缓存、消息队列等技术。
- 自动化配置:
- 根据项目的依赖自动进行配置,减少了手动配置的错误和工作量。
- 例如,当添加了数据库依赖后,Spring Boot 会自动配置数据库连接。
- 监控和管理:
- 提供了 Actuator 模块,可以方便地对应用进行监控和管理,获取应用的运行状态、性能指标等信息。
Spring Boot 的缺点:
- 学习曲线:
- 虽然简化了开发,但对于初学者来说,Spring Boot 涉及的技术栈较多,学习曲线可能仍然较陡。
- 需要了解 Spring 框架的基础知识以及各种配置和集成的方式。
- 内存占用:
- 由于内置了服务器和众多的自动配置,应用启动时可能会占用较多的内存。
- 在资源受限的环境下,可能需要进行优化。
- 复杂性增加:
- 在一些大型项目中,自动配置可能会导致一些难以调试的问题。
- 有时候需要深入了解自动配置的原理,以便进行定制和排除故障。
- 版本更新快:
- Spring Boot 的版本更新速度较快,这可能导致项目在升级时需要进行大量的调整和测试。
- 开发者需要及时跟进新版本的变化,以确保项目的稳定性。
八、Spring boot 的 核心配置文件有哪些?
Spring Boot 的核心配置文件主要有以下两种:
一、application.properties
-
特点:
- 以键值对的形式进行配置。
- 语法简单直观,易于理解和编辑。
-
常见配置项:
- 服务器配置:如端口号(server.port)、上下文路径(server.servlet.context-path)等。
- 数据库连接配置:数据库 URL(spring.datasource.url)、用户名(spring.datasource.username)、密码(spring.datasource.password)等。
- 日志配置:日志级别(logging.level.root)、日志文件路径(logging.file.name)等。
二、application.yml
-
特点:
- 使用 YAML(YAML Ain't Markup Language)格式,具有简洁的语法和良好的可读性。
- 支持层次结构的配置,适合复杂的配置场景。
-
常见配置项示例:
- 服务器配置:
server: port: 8080 servlet: context-path: /myapp
-
数据库连接配置:
spring: datasource: url: jdbc:mysql://localhost:3306/mydb username: myuser password: mypassword
-
日志配置:
logging: level: root: INFO file: name: application.log
九、Spring Boot 最核心的注解有哪些?
@SpringBootApplication:这是一个组合注解标识了这是一个SpringBoot工程,它包含了三个主要的注解:
1,@SpringBootConfiguration:表明这是一个 Spring Boot 的配置类,类似于传统 Spring 中的 XML 配置文件。
2,@EnableAutoConfiguration:开启自动配置功能。Spring Boot 会根据项目中引入的依赖自动配置相应的组件和功能,大大减少了手动配置的工作量。
3,@ComponentScan:扫描当前包及其子包下的 Spring 组件(如 @Service、@Controller、@Repository 等注解标注的类),并将它们纳入 Spring 容器进行管理。
**4,**Conditional
@Conditional注解是一个非常有用的注解,用于根据特定条件来决定是否将一个 bean 注册到 Spring 容器中或者是否启用特定的配置。
- @ConditionalOnBean:当容器中存在指定的 bean 时满足条件。
- 例如:
@Configuration类中某个方法上使用@Bean注解创建一个 bean,并且该方法上添加了@ConditionalOnBean(SomeOtherBean.class),只有当容器中存在SomeOtherBean这个 bean 时,这个方法创建的 bean 才会被注册到容器中。
- 例如:
- @ConditionalOnMissingBean:当容器中不存在指定的 bean 时满足条件。
- 与
@ConditionalOnBean相反,只有当容器中不存在特定类型的 bean 时,才会执行相应的配置或创建相应的 bean。
- 与
- @ConditionalOnClass:当类路径上存在指定的类时满足条件。
- 比如,当类路径上存在某个特定的数据库驱动类时,才进行数据库相关的配置。
- @ConditionalOnMissingClass:当类路径上不存在指定的类时满足条件。
- 与
@ConditionalOnClass相反,只有当类路径上不存在特定的类时,才执行相应的配置。
- 与
- @ConditionalOnProperty:当指定的属性有特定的值时满足条件。
- 可以通过在 application.properties 或 application.yml 等配置文件中设置属性值,然后根据这些属性值来决定是否进行特定的配置。例如,
@ConditionalOnProperty(prefix = "myapp", name = "enabled", havingValue = "true")表示当配置文件中有myapp.enabled=true这个属性时满足条件。
- 可以通过在 application.properties 或 application.yml 等配置文件中设置属性值,然后根据这些属性值来决定是否进行特定的配置。例如,
十、Spring Boot 需要独立的容器运行吗?
Spring Boot 不需要独立的传统应用服务器容器来运行。
Spring Boot 有以下特点使得它可以不依赖独立的传统容器运行:
一、内置容器
-
优势:
- Spring Boot 可以内嵌入 Tomcat、Jetty 或 Undertow 等服务器容器。
- 这使得开发和部署更加便捷,无需单独安装和配置外部的应用服务器。
- 在开发阶段,可以快速启动项目进行调试,提高开发效率。
-
使用方式:
- 当你运行 Spring Boot 应用时,内置的容器会自动启动并监听指定的端口。
- 可以通过配置文件(如 application.properties 或 application.yml)来调整容器的参数,如端口号、上下文路径等。
二、可独立部署
- 特点:
- Spring Boot 应用可以打包成一个可执行的 JAR 或 WAR 文件。
- 如果是 JAR 包,可以直接使用命令行运行,内置容器会随之启动。
- 对于 WAR 包,可以部署到传统的应用服务器中,但这并不是必须的。
三、灵活性
- 与传统容器结合:
- 虽然 Spring Boot 可以独立运行,但如果需要,也可以部署到独立的传统应用服务器容器中。
- 例如,在某些特定的生产环境中,可能已经有了成熟的应用服务器管理体系,此时可以将 Spring Boot 应用以 WAR 包的形式部署到这些容器中。
十一、Spring Boot 自动配置原理是什么?
1,通过@SpringBootApplication 引入了 @EnableAutoConfiguration(负责启动自动配置功能)
2,@EnableAutoConfiguration 引入了 @import
3,Spring容器启动时,加载Ioc容器时会解析@import 注解
4,@import 注解导入了一个DeferredImportSelector 它会使SpringBoot的自动配置类的顺序在最后,这样方便我们扩展和覆盖。
5,然后读取所有的/META-INFO/Spring.factories文件
6,过滤出所有的AutoConfigurtionClass类型的类
7,最后通过@Condition 排除无效的自动配置类
十二、Spring Cloud 注册中心有哪些实现方案?
Spring Cloud 注册中心有以下几种常见的实现方案:
一、Eureka
-
特点:
- 是 Spring Cloud 原生支持的服务注册与发现组件。
- 具有自我保护机制,当网络分区等故障导致部分实例不可用时,不会立即将其从注册表中删除。
- 采用客户端缓存机制,即使注册中心不可用,服务消费者也可以使用本地缓存的服务列表进行调用。
-
使用场景:
- 适用于中小型规模的微服务架构,对服务发现的实时性要求不是特别高的场景。
二、Consul
-
特点:
- 不仅提供服务注册与发现功能,还具备强大的服务配置、健康检查、密钥 / 值存储等功能。
- 支持多数据中心,具有高可用和分布式的特点。
- 提供了丰富的 API 和命令行工具,方便管理和监控。
-
使用场景:
- 适用于大型分布式系统,对服务的高可用性和多数据中心支持有要求的场景。
三、Zookeeper
-
特点:
- 是一个成熟的分布式协调服务,具有高可靠、强一致性等特点。
- 可以用于实现分布式锁、领导选举等功能。
- 对服务的动态感知相对较弱,需要依赖客户端的定时轮询机制。
-
使用场景:
- 如果已经在项目中使用了 Zookeeper 进行其他分布式协调任务,可以考虑将其作为服务注册中心使用
十三、Spring Cloud 有那些重要组件?
Spring Cloud 有以下一些重要组件:
一、Eureka(服务注册与发现)
-
功能:
- 服务提供者将自己注册到 Eureka 服务器上,服务消费者从 Eureka 服务器获取服务列表,实现服务的自动发现。
- 在服务提供者出现故障时,Eureka 能够及时将其从服务列表中剔除,保证服务调用的可靠性。
-
使用场景:
- 在微服务架构中,用于管理和发现各个微服务实例。
二、Ribbon(客户端负载均衡)
-
功能:
- 与服务消费者集成,在调用服务时,根据一定的负载均衡策略从多个服务提供者实例中选择一个进行调用。
- 支持多种负载均衡算法,如轮询、随机等。
-
使用场景:
- 当有多个相同服务的实例时,确保请求能够均衡地分配到各个实例上,提高系统的性能和可靠性。
三、Feign(声明式服务调用)
-
功能:
- 基于 Ribbon 和 Hystrix 实现,通过定义接口的方式来调用其他服务,简化了服务调用的代码。
- 可以自动处理服务调用中的负载均衡、熔断等问题。
-
使用场景:
- 方便地进行服务间的通信,减少了服务调用的代码复杂度。
四、Hystrix(断路器)
-
功能:
- 当某个服务出现故障时,能够快速熔断,阻止故障的扩散。
- 提供降级机制,在服务不可用时返回备用的响应。
-
使用场景:
- 保护整个系统免受个别服务故障的影响,提高系统的稳定性。
五、Zuul(网关)
-
功能:
- 作为微服务架构的统一入口,负责请求的路由、过滤、安全控制等。
- 可以对请求进行鉴权、限流等操作,提高系统的安全性和性能。
-
使用场景:
- 为微服务架构提供统一的对外接口,方便管理和监控所有的服务请求。
六、Config(配置中心)
-
功能:
- 集中管理微服务的配置文件,实现配置的动态更新。
- 服务实例可以从配置中心获取最新的配置信息,无需重新部署即可生效。
-
使用场景:
- 当需要修改多个服务的配置时,只需在配置中心进行一次修改,所有服务都能及时获取到新的配置。
十四、Spring Cloud 中的Feign 是什么?
在 Spring Cloud 中,Feign 是一个声明式的 HTTP 客户端。
一、功能特点
-
简化服务调用:
- Feign 允许开发者通过定义接口的方式来调用其他服务,而无需手动编写大量的 HTTP 请求代码。
- 只需要在接口上添加注解,指定服务的名称和请求的方法、路径等信息,Feign 就会自动生成实现该接口的代理对象,在运行时发起 HTTP 请求。
-
集成 Ribbon 和 Hystrix:
- 默认情况下,Feign 集成了 Ribbon 实现客户端负载均衡。它会根据服务名从注册中心获取服务列表,并按照一定的负载均衡策略选择一个服务实例进行调用。
- 同时,Feign 也可以集成 Hystrix,实现断路器功能。当调用的服务出现故障时,能够快速熔断,避免故障扩散,并提供降级机制返回备用的响应。
-
可扩展性:
- Feign 支持自定义编码器和解码器,可以根据需要对请求和响应进行特殊的处理。
- 还可以通过配置来调整超时时间、重试策略等参数,以满足不同的应用场景需求。
二、使用场景
-
微服务架构中的服务间通信:
- 在微服务架构中,各个服务之间需要进行频繁的通信。使用 Feign 可以简化服务调用的代码,提高开发效率。
- 例如,一个订单服务需要调用商品服务获取商品信息,使用 Feign 可以通过定义一个商品服务的接口,直接在订单服务中调用该接口,而无需关心底层的 HTTP 请求细节。
-
跨语言服务调用:
- 虽然 Feign 主要用于 Java 微服务之间的调用,但也可以通过一些扩展实现跨语言的服务调用。
- 例如,使用 Feign 与其他语言实现的服务进行交互,可以通过定义一个通用的 RESTful API 接口,然后使用 Feign 调用该接口,实现不同语言服务之间的集成。
十五、什么是服务熔断?
服务熔断是一种在微服务架构中用于应对服务故障的机制。
一、定义与原理
-
概念:
- 当某个服务出现故障或者响应时间过长时,为了防止故障的扩散和对整个系统的影响,熔断器会自动切断对该服务的调用,这种行为就称为服务熔断。
- 就像电路中的保险丝一样,当电流过大时会自动熔断,保护电器设备不受损坏。
-
工作原理:
- 熔断器通常会维护一个状态机,有三种状态:关闭(Closed)、打开(Open)和半打开(Half-Open)。
- 当服务正常时,熔断器处于关闭状态,允许对服务的调用。如果调用失败的次数超过一定阈值,熔断器会切换到打开状态,此时所有对该服务的调用都会被快速失败,直接返回预设的降级响应。
- 经过一段时间后,熔断器会进入半打开状态,允许少量的请求通过,以探测服务是否已经恢复。如果这些请求成功,熔断器会切换回关闭状态;如果请求失败,熔断器会再次切换到打开状态。
二、作用与优势
-
防止故障扩散:
- 在微服务架构中,一个服务的故障可能会导致调用它的其他服务也出现故障,形成连锁反应。服务熔断可以在故障发生时及时切断对故障服务的调用,防止故障扩散到整个系统。
- 例如,一个电商系统中的商品服务出现故障,如果没有服务熔断,订单服务在调用商品服务时可能会一直等待或者抛出异常,导致订单服务也无法正常工作,进而影响整个系统的稳定性。
-
提高系统的可用性:
- 通过快速失败和返回降级响应,服务熔断可以避免用户长时间等待或者收到错误响应,提高系统的可用性。
- 例如,当商品服务不可用时,订单服务可以返回一个默认的商品列表或者提示用户商品信息暂时无法获取,而不是让用户一直等待或者收到错误页面。
-
保护服务资源:
- 当服务出现故障时,如果没有服务熔断,大量的请求可能会堆积在服务端,消耗大量的系统资源,甚至导致服务崩溃。服务熔断可以避免这种情况的发生,保护服务资源。
- 例如,当商品服务出现性能问题时,大量的请求可能会导致商品服务的数据库连接耗尽、内存溢出等问题。服务熔断可以及时切断对商品服务的调用,避免这些问题的发生。
十六、启动熔断降级服务的注解
在 Spring Cloud 中,通常使用 @HystrixCommand 注解来启动熔断降级服务。
一、@HystrixCommand 注解的功能
-
定义熔断降级方法:
- 通过在方法上添加
@HystrixCommand注解,可以指定该方法在触发熔断降级时的备用逻辑。 - 例如,可以定义一个方法,当调用的服务出现故障时,返回一个默认值或者执行其他替代操作。
- 通过在方法上添加
-
配置熔断参数:
@HystrixCommand注解可以接受多个参数,用于配置熔断降级的行为。- 例如,可以设置熔断的超时时间、请求失败的阈值、降级方法等。
二、使用示例
以下是一个使用 @HystrixCommand 注解的示例:
import org.springframework.stereotype.Service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
@Service
public class MyService {
@HystrixCommand(fallbackMethod = "fallbackMethod")
public String callExternalService() {
// 调用外部服务的代码,如果出现故障,会触发熔断降级
return "External service response";
}
public String fallbackMethod() {
// 熔断降级时的备用逻辑
return "Fallback response";
}
}
在上面的示例中,callExternalService 方法上添加了 @HystrixCommand 注解,并指定了 fallbackMethod 作为熔断降级时的备用方法。当调用外部服务出现故障时,会自动调用 fallbackMethod 方法返回备用响应。
十七、Spring Cloud Eureka 保护机制是什么?
Spring Cloud Eureka 的自我保护机制是一种在特定情况下防止服务实例被错误地从注册中心剔除的机制。
一、自我保护机制的原理
-
触发条件:
- 当 Eureka Server 在一定时间内(默认 15 分钟)没有收到某个微服务实例的心跳时,Eureka Server 会将该实例从服务注册表中剔除。但是,当网络分区等故障发生时,可能会导致部分实例的心跳无法正常发送到 Eureka Server,此时如果 Eureka Server 按照正常逻辑剔除这些实例,可能会导致服务发现出现问题。
- 为了避免这种情况,Eureka Server 引入了自我保护机制。当 Eureka Server 统计到在一定时间内(默认 15 分钟)有超过 85% 的微服务实例的心跳都没有正常更新时,Eureka Server 会进入自我保护模式。
-
行为表现:
- 在自我保护模式下,Eureka Server 不会剔除任何服务实例,即使这些实例的心跳已经超时。
- Eureka Server 仍然会接收新的服务注册和心跳,但是不会对服务实例进行过期处理。
- 当网络故障恢复后,这些实例的心跳会重新开始更新,Eureka Server 也会自动退出自我保护模式。
二、自我保护机制的作用
-
提高服务可用性:
- 在网络分区等故障情况下,自我保护机制可以防止服务实例被错误地剔除,从而保证服务发现的准确性和稳定性。
- 即使部分实例的心跳无法正常发送到 Eureka Server,服务消费者仍然可以从注册中心获取到这些实例的信息,并进行服务调用。
-
减少服务中断时间:
- 如果没有自我保护机制,当网络故障发生时,可能会导致大量的服务实例被剔除,服务消费者在进行服务调用时可能会出现找不到服务的情况,从而导致服务中断。
- 有了自我保护机制,服务消费者可以继续使用已经注册的服务实例,减少了服务中断的时间。
十八、Spring Cloud Feign 和ribbon 的区别?
Spring Cloud Feign 和 Ribbon 都是在微服务架构中用于服务调用的组件,但它们有以下区别:
一、功能定位
-
Feign:
- 是一个声明式的 HTTP 客户端。
- 主要功能是通过定义接口的方式来简化服务调用,使得开发者可以像调用本地方法一样调用远程服务。
- 它集成了 Ribbon 和 Hystrix,实现了负载均衡和断路器功能。
-
Ribbon:
- 是一个客户端负载均衡器。
- 主要负责在服务消费者端根据一定的负载均衡策略从多个服务提供者实例中选择一个进行调用。
- 它本身不具备服务调用的功能,需要与其他组件(如 RestTemplate)结合使用。
二、使用方式
-
Feign:
- 使用时,开发者只需要定义一个服务接口,并在接口上添加注解,指定服务的名称和请求的方法、路径等信息。
- Feign 会根据这些注解自动生成实现该接口的代理对象,在运行时发起 HTTP 请求。
- 例如:
@FeignClient("service-provider") public interface MyServiceClient { @GetMapping("/api/data") String getData(); }
-
Ribbon:
- 需要在服务消费者的配置文件中配置 Ribbon 的相关参数,如服务名称、负载均衡策略等。
- 在代码中,使用 RestTemplate 发起 HTTP 请求,并通过 Ribbon 的负载均衡功能选择服务提供者实例。
- 例如:
@Autowired private RestTemplate restTemplate;
public String getData() { return restTemplate.getForObject("http://service-provider/api/data", String.class); }
三、集成程度
-
Feign:
- 高度集成了负载均衡和断路器功能,开发者无需额外配置即可使用这些功能。
- 提供了更简洁的 API,减少了代码量。
-
Ribbon:
- 需要与其他组件结合使用,配置相对复杂一些。
- 但也提供了更多的灵活性,可以根据具体需求进行定制化配置。
总结:
Feign 和 Ribbon 在微服务架构中都起着重要的作用。Feign 提供了更简洁的服务调用方式,集成了负载均衡和断路器功能;而 Ribbon 则专注于客户端负载均衡,可以与其他组件灵活组合使用。在实际应用中,可以根据项目的具体需求选择使用其中一个或两个组件结合使用。