# SpringBoot 自动装配原理
- @SpringBootApplication (main 方法上的注解)
- @EnableAutoConfiguration (自动装配核心注解)
- 导入 AutoConfigurationImportSelector 组件
- 通过 SpringFactoriesLoader 类读取
- META-INF/spring.factories
- org.springframework.boot.autoconfigure.AutoConfiguration.imports
- 条件注解进行过滤 (只有导入了相关 jar 包才会进行配置)
- ImportSelector 接口
- BeanDefinition
- 实例化 Bean 对象,放入 Spring 的 IOC 容器中
# 如何实现 Spring Boot Starter
- 写一个 starter 项目,一般是一个空壳,里面不写代码,主要起到 依赖其他项目的作用;
- 写一个真正实现自动装配逻辑的项目,在项目 classpath 下写一个 META-INF/spring.factories 文件;
- 在 spring.factories 中添加配置:org.springframework.boot.autoconfigure.EnableAutoConfigure = com.kablog.XXXConfiguration
- XXXConfiguration 类需要添加注解 @Configuration;
- 上述类一般使用 @Conditional 来适应不同的环境;
- 在 XXXConfiguration 类中编写具体代码实现自动化配置,给使用者把该配的配置好,让他人可以直接使用
# Spring Boot 与 SSM 有什么区别和优势
- SSM10 随版本更新,依赖越来越多,配置越来越多,需要配置大量 xml 文件,开发繁琐
- SpringBoot 约定优于配置,采用自动化配置,自动装配 Bean, 无需 SSM 一样的繁琐配置
- SpringBoot 直接使用 java main 方法运行,可直接内嵌 Tomcat 服务器运行 SpringBoot 程序
- SpingBoot 采用 starter 依赖简化 Maven 配置,自动管理所有 jar 包版本,加入 web starter, 自动引入内嵌的 Tomcat; 当然还提供了大量的 starter
- SpringBoot 可以直接打包成 jar 包运行,部署简单
# Spring Boot 项目如何兼容老的 Spring 项目
- 使用 @ImportResource 注解导入旧配置文件
# JavaConfig
@Configuration
: 使用@Configuration
+ 类 替代 xml 文件对 bean 定义@Bean
: 在 @Configuration 中@Bean
替代<bean id = "XX" class = "XX"></bean>
@ComponentScan
: 使用@ComponentScan(basePackage="XX")
+ 类 替代<context:componentscan basepackage = "XX">
\@EnableWebMvc
: 使用EnableWebMvc
替代<mvc:annotation-driven>
@ImportResource
: 使用@ImportResource(locations = "classpath:xxx.xml")
+ 类 替代<import resource = "xxx.xml">
@Properties
: 使用@Properties("classpath:*.properties")
+ 类 替代<context:property-placeholder location="classpath:*.properties">
@Value
: 使用@Value("${jdbc.xxx}")
来配置数据源
使用注解来开发项目
# 如何排除某些类的自动装配
某些时候配置了如 mybatis-starter 等依赖包,它会自动装配。此时若没有在 properties 中填入相应的 host/port/password/url
等内容,那么运行就会报错。此时应先排除自动装配
在
properties
文件中添加spring.autoconfigure.exclude = org.xxx.DataSourceAutoConfiguration
在类上添加注解
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,xxx.class})
# 如何实现异步调用
# 是什么
asynchronous call (异步调用): 一个无需等待被调用函数的返回值就能让操作继续进行的方法;
# 使用场景
- 对于一些不需要在主线流程中执行的任务:如注册时发送欢迎短信
- 不需要实施等待计算结果的任务:如业务执行记录日志
- 为了利用多核 cpu 并发执行的任务:如下单时获取用户住址,用户余额,商品信息
# 怎么解决
将这些任务异步执行,即放在另一个线程中去执行,从而避免主线程的阻塞和等待
- 方式一:@EnableAsync + @Async + Future + ThreadPoolTaskExecutor
- 方式二:CompletableFuture + ThreadPoolTaskExecutor
# SpringBoot 默认使用什么动态代理
默认使用 CGLIB 动态代理而不是 JDK 动态代理
主要是考虑兼容性
CGLIB 动态代理可以代理任何类型的目标类,而 JDK 动态代理只能代理实现了接口的目标类,
因此 CGLIB 覆盖了 JDK 所有使用场景,故为了保证 SpringBoot 中的 AOP 可以面向任何类型的 Bean,
SpringBoot 默认使用 CGLIB 作为代理的实现方式.
# SpringCloud 组件
- 注册中心:
Eureka,Nacos,Zookeeper,Consul;(服务注册) - 负载均衡:Ribbon,LoadBalancer;(客户端的负载均衡)
- 服务调用:
Feign,OpenFeign,Dubbo RPC;(优雅调用远程服务) - 配置中心:Spring Cloud Config,Nacos;(统一管理服务配置)
- 熔断降级:
Hystrix,Sentinel;(急骤请求,防止服务雪崩) - 分布式事务:Seata;(跨库跨服务的事务管理)
- 服务网关:
Zuul 1.x,Zuul 2.x,Spring Cloud Gateway;(系统入口门面) - 链路跟踪:Skywalking,Zipkin;(监控服务状态,协助排查问题)
# Spring Cloud 的理解
- 将微服务面临的负载均衡,服务的注册与发现,服务调用,服务路由,服务熔断等技术问题解决方案打包好.
- 提供了一整套微服务解决方案,降低开发难度,提供统一标准
- 为 Spring 生态注入更强的生命力
# 服务熔断?服务降级?
服务熔断:当服务 A 调用服务 B 时,如果此时服务 B 不可用,那么上游的服务 A 为了保证自己不受影响,就切断调用服务 B, 防止发生服务雪崩,直到 B 服务恢复.(具体指提前做好一种兜底措施,比如返回假的数据,或者记录数据信息到数据库,redis, 文件中,后续进行补救,直到 B 服务恢复)
服务降级:当系统负载过高时,对非核心的业务服务进行关闭,来保证核心业务的正常运行;(关闭某些不重要的服务,或者拒绝低优先级应用的服务请求,保证核心应用正常工作)
相同:目的相同:保证服务可用性,防止系统整体负载过大甚至崩溃;
表现相同:都是表现出服务暂时不可用的状态
不同:服务熔断一般是某个服务 (下游服务) 故障引起,而服务降级一般是从整体负荷考虑.
# 项目重构时为何要对系统进行拆分
# Eureka 和 Nacos 区别
相同:1. 都用于服务的注册与发现 2. 都支持服务的心跳健康检查 3. 都支持高可用
不同:
Nacos Eureka 支持主动对微服务状态检测,临时实例心跳检测,永久实例主动检测 临时实例不正常会从注册中心删除,永久实例不会删除 支持服务列表变更时的主动消息推送,服务列表更新会更及时 集群支持两种模式,默认 AP, 存在非临时实例时采用 CP 模式 只支持 AP 支持注册中心,配置中心 只支持注册中心 具备较好上下线流量管理界面 后台界面仅供展示,需使用 API 操作上下线,无流量管理 社区活跃 闭源
# ACID,BASE 理论,CAP 理论的关系
# ACID
ACID 是传统数据库中常用的设计理念
- Atomicity (原子性)
- Consistency (一致性)
- Isolation (隔离性)
- Durability (持久性)
ACID 它追求的是数据的强一致性模型
# BASE 理论
BASE 理论支持的是大型分布式系统;
- 基本可用 (Basically Available): 分布式系统出现不可预知故障时,允许损失部分可用性
- 软状态 (Soft State): 允许系统中的数据存在中间状态,允许系统在不同节点的数据副本之间同步存在延时
- 最终一致性 (Eventually Consistent): 所有数据副本在一段时间同步后最终一致的状态,无需实时保证系统数据强一致
BASE 理论是通过牺牲强一致性以获得高可用性
# CAP 理论
CAP 理论是支持分布式系统而提出的;
- C: 一致性 (Consistency)
- A: 可用性 (Availability)
- P: 分区容错性 (Tolerance of network Partition)
分布式系统无法做到 CAP, 只能做到其中两项,要么 CP, 要么 AP
# 三者关系
ACID 和 CAP,BASE 代表了两种截然相反的设计哲学;
在分布式系统设计中,根据不同场景的实际情况,可以把 ACID,CAP,BASE 结合起来使用
# 注册中心选择 CP 还是 AP
简单来说,应该优先选择 AP (可用性) 然后保证最终一致性即可,而选择 CP (一致性) 的话,随着应用规模增大,应用实例频繁注册或删除,必将影响注册中心服务注册与发现的效率.
# 接口幂等性
幂等性 = 多次执行无副作用
考虑幂等性即考虑多次执行,多次请求的情况
在以下场景可能会使用到
- 因网络波动引起的重复请求
- 用户重复操作 (无意触发或因无响应而有意触发等)
- 应用使用了失败或超时重试机制 (如 RPC 重试,业务层重试等)
- 第三方平台的接口 (如:支付成功回调接口), 因为异常导致多次回调
- 中间件 / 应用服务根据自身特性,也有可能进行重试
- 用户双击提交按钮
- 用户页面重复刷新
- 使用浏览器后退按钮重复之前的操作,导致重复提交表单
- 使用浏览器历史记录重复提交表单
- 浏览器重复的 http 请求
- 定时任务重复执行
一般在数据访问层进行幂等性的设计
使用唯一索引防止幂等性问题:简单粗暴,当数据重复时会抛出异常,保证不会出现脏数据
使用 Token+Redis 的幂等方案 (申请 token 阶段和业务操作阶段): 先获得 token 存入 redis, 根据 token 执行处理,然后删除 token. 重复请求时,由于缓存中没有 token, 表示非法请求
# 分布式事务
事务通常用于数据库领域
事务是指对数据库进行读或写的一组操作,要么都执行,要么都不执行,不允许只执行一部分的情况;
由 insert,delete,update,select 组成的一组操作,要么都 commit, 要么都 rollback
本地事务:仅支持单库事务,保证 ACID
分布式事务:多个库,因此有多个数据源的连接,不能使用 spring 的事务管理
分布式事务解决方案
- 2PC
- 3PC
- TCC
- 本地消息异步确认
- 可靠消息最终一致性
- 最大努力通知
- RocketMQ 解决分布式事务
- 阿里巴巴的 Seata 解决分布式事务
如何进行服务的限流
- 计数器法
- 漏桶算法
- 令牌桶算法 (Guava 框架)
分布式环境如何进行服务的限流
- Nginx 限流
- OpenResty 限流
- Sentinel 限流
- Redis + Lua 限流
- Spring Cloud Gateway 限流