Spring AOP 面向切面编程深度解析
Spring AOP一、AOP 基础概念AOP 就是面向切面编程,本质上是对面向对象的补充,毕竟是切面对象,AOP 可以有两种实现方法,一种是动态代理,一种是使用 Spring 来实现,Spring 的话重在会用注解,这里详细讲讲前者,如果是动态代理实现 AOP 的话首先要定义接口,毕竟这样才方便使用动态代理对象执行方法。 二、代理模式代理模式分为两种,动态代理和静态代理。动态代理是一种在运行时生成代理对象的技术,主要是生成一个增强之后的原始对象,当然还有控制访问的作用。而且动态代理有两种,一种是基于反射的 JDK 动态代理,一种是基于继承的 cglib 动态代理,当然还有静态代理,不过没有动态代理灵活。 三、JDK 动态代理实现要点JDK 动态代理的实现有三个关键点,目标接口,目标对象实现目标接口,代理对象实现目标接口,而且代理对象和目标对象是平级关系,关键类有两个,分别是 Proxy 和 InvocationHandler 类,然后就是调用 Proxy 的静态方法 newProxyInstance 创建新的代理实例,接着在 InvocationHandler 中重写 invo...
Spring Bean 生命周期深度解析
Spring Bean 生命周期生命周期完整流程1️⃣ Bean 的创建(实例化)步骤 1:实例化对象 Spring 启动,扫描或加载配置,查找并加载需要被 Spring 管理的 bean,进行 Bean 的实例化,doCreateBean() → createBeanInstance() 实例化对象。 2️⃣ 依赖注入(populateBean)步骤 2:属性赋值 Bean 实例化后对 Bean 的属性进行赋值(依赖注入),populateBean 阶段完成依赖注入,尚未执行初始化逻辑。 3️⃣ Aware 接口回调步骤 3:BeanNameAware 如果 Bean 实现了 BeanNameAware 接口的话,Spring 将 Bean 的 Id 传递给 setBeanName()方法。 步骤 4:BeanFactoryAware 如果 Bean 实现了 BeanFactoryAware 接口的话,Spring 将调用 setBeanFactory()方法,将 BeanFactory 容器实例传入。 步骤 5:ApplicationContextAware 如果 Bean ...
Spring 事务失效场景深度解析
Spring 事务失效一、底层原理Spring 事务是 AOP 实现的,通过 TransactionInterceptor 包装目标方法,生成代理对象(JDK 动态代理 / CGLIB),方法调用时先经过拦截器,根据事务回滚默认规则,决定是否开启事务、提交或回滚。 方法调用时先经过拦截器,拦截器就是 Spring 为 @Transactional 创建的 TransactionInterceptor。它被织入代理对象的拦截器链里,JDK 动态代理通过 InvocationHandler,CGLIB 通过 MethodInterceptor,调用代理对象方法时会先执行 TransactionInterceptor,然后再执行目标方法。 TransactionInterceptor.invoke() 本身只负责事务逻辑,它位于代理对象的拦截器链中。方法调用时先进入拦截器链,每个拦截器依次调用 invoke(),TransactionInterceptor 内部直接调用 method.invoke(target, args) 是为了执行链中下一个环节或最终目标方法。拦截器链的...
Spring 循环依赖问题深度解析
Spring 循环依赖什么是循环依赖循环依赖指的是两个类中的属性相互依赖对方:例如 A 类中有 B 属性,B 类中有 A 属性,从而形成了一个依赖闭环。 循环依赖的三种情况循环依赖问题在 Spring 中主要有三种情况: 第一种:通过构造方法进行依赖注入时产生的循环依赖问题 构造器注入类似原因:创建对象必须传完整依赖,提前暴露也无法注入 → 无法解决。 第二种:通过 setter 方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题 原型 Bean 循环依赖无法解决,因为容器不会缓存半初始化对象,每次 getBean 都创建新实例,无法注入引用。容器不缓存 Bean,单例 Bean 会放入 singletonObjects(一级缓存),原型 Bean 不会放入一级缓存,更不会维护二级缓存(earlySingletonObjects)或三级缓存(singletonFactories),所以每次获取原型 Bean,Spring 都是 “全新创建 + 注入 + 初始化”,容器不会提前暴露半初始化对象。 第三种:通过 setter 方法进行依赖注入且是在单例模式下产生的循环依赖问题...
Spring IOC 容器深度解析
Spring IOC一、基础介绍什么是 IOCIOC:Inversion Of Control,即控制反转,是一种设计思想。在传统的 Java SE 程序设计中,我们直接在对象内部通过 new 的方式来创建对象,是程序主动创建依赖对象而在 Spring 程序设计中,IOC 是有专门的容器去控制对象。所谓控制就是对象的创建、初始化、销毁。 创建对象: 原来是 new 一个,现在是由 Spring 容器创建。 初始化对象: 原来是对象自己通过构造器或者 setter 方法给依赖的对象赋值,现在是由 Spring 容器自动注入。 销毁对象: 原来是直接给对象赋值 null 或做一些销毁操作,现在是 Spring 容器管理生命周期负责销毁对象。 控制反转的含义IOC 解决了繁琐的对象生命周期的操作,解耦了我们的代码。所谓反转:其实是反转的控制权,前面提到是由 Spring 来控制对象的生命周期,那么对象的控制就完全脱离了我们的控制,控制权交给了 Spring 。这个反转是指:我们由对象的控制者变成了 IOC 的被动控制者。 依赖注入(DI)依赖注入(DI)是实现这种技术的一种方式。传统开...
Spring 微服务组件深度解析
Spring 微服务组件 微服务组件 注册中心 注册中心是微服务架构最核心的组件。它起到的作用是对新节点的注册与状态维护,解决了「如何发现新节点以及检查各节点的运行状态的问题」。微服务节点在启动时会将自己的服务名称、IP、端口等信息在注册中心登记,注册中心会定时检查该节点的运行状态。注册中心通常会采用心跳机制最大程度保证已登记过的服务节点都是可用的。 配置中心 配置中心主要解决了「如何集中管理各节点配置文件的问题」,在微服务架构下,所有的微服务节点都包含自己的各种配置文件,如 jdbc 配置、自定义配置、环境配置、运行参数配置等。要知道有的微服务可能可能有几十个节点,如果将这些配置文件分散存储在节点上,发生配置更改就需要逐个节点调整,将给运维人员带来巨大的压力。配置中心便由此而生,通过部署配置中心服务器,将各节点配置文件从服务中剥离,集中转存到配置中心。一般配置中心都有 UI 界面,方便实现大规模集群配置调整。 负载均衡 简单轮询 将请求按顺序分发给后端服务器上,不关心服务器当前的状态,比如后端服务器的性能、当前的负载。 加权轮询 根据服务器自身的性能给服务器设置不同...
Spring 自动装配原理深度解析
Spring 自动装配原理一、基础介绍SpringBoot 的自动装配原理是基于 Spring Framework 的条件化配置和@EnableAutoConfiguration 注解实现的。这种机制允许开发者在项目中引入相关的依赖,SpringBoot 将根据这些依赖自动配置应用程序的上下文和功能。 SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的 META-INF/Spring.factories 文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。 通俗来讲,自动装配就是通过注解或一些简单的配置就可以在 SpringBoot 的帮助下开启和配置各种功能,比如数据库访问、Web 开发。 二、实现原理@EnableAutoConfiguration 核心注解@EnableAutoConfigura...
RocketMQ 其他特性深度解析
RocketMQ 其他特性一、延时 / 定时消息实现延迟消息(Scheduled Message)是指生产者发送的消息 不会立即被消费者消费,而是延迟一定时间后才可被消费。 RocketMQ 延迟消息通过 延迟级别 + 定时投递 实现: 1️⃣ Producer 发送延迟消息时指定 DelayLevel,消息写入 CommitLog 并标记延迟级别 2️⃣ Broker 的定时调度线程扫描延迟消息,检查延迟时间是否到达 3️⃣ 延迟时间到达后,将消息投递到普通队列,Consumer 可正常消费 延迟消息本质上还是普通消息,只是 消费可见性被延迟。RocketMQ 并没有单独的延迟队列,而是通过 定时任务 + 队列偏移控制 实现延迟投递。 二、过滤消息实现支持 Tag过滤(服务器端) 和 SQL92表达式过滤消息属性,消息发送时可设置属性,消费者订阅时使用 Tag 或 SQL 表达式。Broker 优先做服务器端过滤,消费端可做二次过滤。 三、为什么不使用 Kafka?性能与适用场景Kafka在数据吞吐上是远超rocketmq的,但是它的topic很多的情况下,性能又远低...
RocketMQ 死信队列机制深度解析
RocketMQ 死信队列什么是死信队列当一条消息消费失败,RocketMQ就会自动进行消息重试。而如果消息超过最大重试次数,RocketMQ就会认为这个消息有问题。但是此时,RocketMQ不会立刻将这个有问题的消息丢弃,而会将其发送到这个消费者组对应的一种特殊队列:死信队列。 死信队列的特征1. 队列归属 一个死信队列对应一个ConsumGroup,而不是对应某个消费者实例。如果一个ConsumeGroup没有产生死信消息,RocketMQ就不会为其创建相应的死信队列。 2. 消费行为 死信队列中的消息不会再被消费者正常消费。 3. 有效期 死信队列的有效期跟正常消息相同。默认3天,对应broker.conf中的fileReservedTime属性。超过这个最长时间的消息都会被删除,而不管消息是否消费过。 死信消息的处理通常,一条消息进入了死信队列,意味着消息在消费处理的过程中出现了比较严重的错误,并且无法自行恢复。此时,一般需要人工去查看死信队列中的消息,对错误原因进行排查。然后对死信消息进行处理,比如转发到正常的Topic重新进行消费,或者丢弃。
RocketMQ 集群高可用方案深度解析
RocketMQ 集群高可用一、故障型高可用多节点部署以便故障转移如果Broker以一个集群的方式部署,会有一个master节点和多个slave节点,消息需要从Master复制到Slave上。而消息复制的方式分为同步复制和异步复制。 同步复制: 同步复制是等Master和Slave都写入消息成功后才反馈给客户端写入成功的状态,同步复制会增大数据写入的延迟,降低系统的吞吐量。 异步复制: 异步复制是只要master写入消息成功,就反馈给客户端写入成功的状态。然后再异步的将消息复制给Slave节点在异步复制下,系统拥有较低的延迟和较高的吞吐量。但是如果master节点故障,而有些数据没有完成复制,就会造成数据丢失。 RocketMQ 的主从架构中,Master 是消息的写入和读取主节点,而 Slave 主要是复制 Master 消息,用于容灾和故障转移。 二、容量型高可用消息积压处理RocketMQ 消息积压是指 Broker 中待消费消息堆积过多,消费者消费速度跟不上生产者发送速度。 处理方法主要包括: 1️⃣ 监控队列堆积指标,及时发现问题 2️⃣ 对生产者进行流控或延迟发送,缓...