加载中...


springboot-actuator

SpringBoot监控神器-Actuator保姆级教程 手把手教你实现SpringBoot的监控! Spring Cloud应用的优雅下线与灰度发布

springboot-admin

Spring Boot Admin横空出世! Spring Boot Admin服务监控利器

springboot-aop

aop execution表达式

类别 函数 入参 说明
方法切点函数 execution() 方法匹配模式串 表示满足某一匹配模式的所有目标类方法连接点。如execution(* greetTo(..))表示所有目标类中的greetTo()方法。 *
@annotation() 方法注解类名 表示标注了特定注解的目标方法连接点。如@annotation(com.baobaotao.anno.NeedTest)表示任何标注了@NeedTest注解的目标类方法。
方法入参切点函数 args() 类名 通过判别目标类方法运行时入参对象的类型定义指定连接点。如args(com.baobaotao.Waiter)表示所有有且仅有一个按类型匹配于Waiter的入参的方法。
@args() 类型注解类名 通过判别目标方法的运行时入参对象的类是否标注特定注解来指定连接点。如@args(com.baobaotao.Monitorable)表示任何这样的一个目标方法:它有一个入参且入参对象的类标注@Monitorable注解。
目标类切点函数 within() 类名匹配串 表示特定域下的所有连接点。如within(com.baobaotao.service.*)表示com.baobaotao.service包中的所有连接点,也即包中所有类的所有方法,而within(com.baobaotao.service.*Service)表示在com.baobaotao.service包中,所有以Service结尾的类的所有连接点。
target() 类名 假如目标类按类型匹配于指定类,则目标类的所有连接点匹配这个切点。如通过target(com.baobaotao.Waiter)定义的切点,Waiter、以及Waiter实现类NaiveWaiter中所有连接点都匹配该切点。
@within() 类型注解类名 假如目标类按类型匹配于某个类A,且类A标注了特定注解,则目标类的所有连接点匹配这个切点。 如@within(com.baobaotao.Monitorable)定义的切点,假如Waiter类标注了@Monitorable注解,则Waiter以及Waiter实现类NaiveWaiter类的所有连接点都匹配。
@target() 类型注解类名 目标类标注了特定注解,则目标类所有连接点匹配该切点。如@target(com.baobaotao.Monitorable),假如NaiveWaiter标注了@Monitorable,则NaiveWaiter所有连接点匹配切点。
代理类切点函数 this() 类名 代理类按类型匹配于指定类,则被代理的目标类所有连接点匹配切点。这个函数比较难理解,这里暂不举例,留待后面详解。

相关文章

深入聊一聊Spring AOP实现机制! Spring AOP,应该不会有比这更详细的介绍了! Spring AOP、AspectJ、CGLIB都是什么关系?
似懂非懂的AspectJ Spring AOP与AspectJ有什么区别和联系? 如果抛开Spring,如何自己实现AOP?
图解Spring AOP实现原理 Spring Boot中的AOP,到底是JDK还是Cglib动态代理? @After,@Around,@Before的执行顺序※
Spring中一个少见的引介增强IntroductionAdvisor Spring AOP中,切点有多少种定义方式? Spring AOP中的代理对象是怎么创建出来的?

springboot-dynamicDB

spring boot使用AbstractRoutingDataSource实现动态数据源切换 Spring Boot如何动态切换多数据源? dynamic-datasource-spring-boot-starter
如何自定义SpringBoot多数据源的starter组件 手把手教你玩多数据源动态切换-dynamicDB1 Spring Boot实现MySQL读写分离技术-dynamicDB2
Spring Boot多数据源及事务解决方案 SpringBoot实现动态切换数据源,这样做才更优雅!

springboot-feature

参数读取

SpringBoot多种读取配置文件中参数的方式 SpringBoot的@Value注解,高级特性,真心强大! Spring Boot中yaml文件:定义list集合、数组及注意事项
6种方式读取SpringBoot的配置,老鸟都这么玩(原理+实战) Spring Boot优雅加载配置文件的几种姿势! 如何不重新编译让Spring Boot配置文件生效

druid

Spring Boot如何统计、监控SQL运行情况? 使用druid进行数据库加密

优化

Spring Boot深度调优,6得飞起~ Spring Boot这样优化,让你的项目飞起来! 7种方式,教你提升Spring Boot项目的吞吐量
SpringBoot内置Tomcat线程数优化配置,你学会了吗 这样优化,0.059s启动一个SpringBoot项目 7min到40s:Spring Boot启动优化实践

other

优雅的实现Spring Boot异步线程间数据传递 Spring Boot请求路径可以定义成/**/**这种格式吗? 你绝对不知道的SpringBoot的外部化配置特性!
Spring Boot如何实现插件化开发模式 Spring Boot业务组件化开发,维护起来很香 try-catch这样写才足够优雅
请不要自己写,Spring Boot非常实用的内置功能

模式

巧妙利用SpringBoot应用责任连模式,让编程事半功倍 SpringBoot使用装饰器模式

业务

Spring Boot实现抽奖大转盘 Spring Boot接入支付宝完整流程实战 用了6年的Spring Boot项目部署方案!打包+Shell脚本部署详解,稳的一批!
Spring Boot+Prometheus+Grafana打造可视化监控一条龙! 监控神器:Prometheus轻松入门,真香 如何把Spring Boot的Jar包做成exe?
如何把java代码,打包成jar文件并转换为exe可执行文件? 手把手教你用Jenkins自动部署SpringBoot! Spring Boot使用Disruptor做内部高性能消息队列
SpringBoot+Vue实现微信扫码支付、退款功能 Spring Boot应用该如何预防XSS攻击 ? Spring Boot整合Canal+RabbitMQ监听数据变更
SpringBoot整合RocketMQ,尝尝几大高级特性! Spring Boot实现MySQL百万级数据量导出并避免OOM的解决方案 SpringBoot整合MinIO实现视频的分片上传/断点续传
Spring Boot项目Jar包加密,防止反编译 Spring Boot接口防抖(防重复提交),轻松搞定 SpringBoot+mail轻松实现各类邮件自动推送
SpringBoot + AOP编程,轻松搞定审计日志 SpringBoot实战:文件上传之秒传、断点续传、分片上传 Spring Boot+Bucket4j实现API请求限流
Spring Boot + Canal实现数据库变化的实时监控 Spring Boot关于日期时间格式化处理方式总结 一个依赖搞定Spring Boot反爬虫,防止接口盗刷!
Spring Boot实现服务热部署的正确姿势 SpringBoot 优雅停机的正确姿势 Spring Boot别再用Date作为入参了,LocalDateTime、LocalDate真香!
SpringBoot玩一玩代码混淆,防止反编译代码泄露 Spring Boot + Spring Batch实现批处理任务 SpringBoot+Filter实现Gzip压缩超大json对象,传输耗时大大减少
Spring Boot配置日志输出的正确姿势!

retry

Spring中的重试机制,简单、实用!(Spring Retry) 重试框架Spring-Retry和Guava-Retry,你知道该怎么选吗? Java远程调用失败?如何优雅的进行重试?
Spring Boot中使用spring-retry轻松解决重试 接口请求重试的8种方法,你用哪种?

Thymeleaf模板引擎

Thymeleaf快速入门 细品Spring Boot+Thymeleaf,还有这么多好玩的细节!

Spring-Boot-Devtools

Spring Boot应用支持热部署,无需手动重启Spring Boot应用,spring-boot-devtools是一个为开发者服务的一个模块,其中最重要的功能就是修改代码后自动启动springboot服务,速度比手动停止后再启动要快,节省出来的并不是手工操作的时间,具体原理主要是使用了两个ClassLoader,一个Classloader加载不会改变的类(第三方Jar包),另一个ClassLoader加载会更改的类,称为restart ClassLoader,这样在有代码更改的时候,原来的restartClassLoader被丢弃,重新创建一个restartClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间
Spring Boot开发环境热部署(HotSwap)详解

springboot-flowable

Spring Boot + Flowable快速实现工作流,So Easy! Spring Boot整合流程引擎Flowable,so easy! SpringBoot+Vue+Flowable,模拟一个请假审批流程!
49张图带领小伙伴们体验一把Flowable-UI Spring Security + Vue + Flowable怎么玩? 极简Java工作流概念入门
RuoYi-flowable:基RuoYi-vue + flowable 6.7.2的工作流管理 Flowable79张表都是干嘛的? 请假要组长和经理同时审批该怎么办?来看看工作流中的会签功能!
一个不用写代码的案例,来看看Flowable到底给我们提供了哪些功能? 手把手教大家编译flowable源码 手把手教大家在Spring Boot中处理flowable中的用户和组!
Flowable流程部署与删除 玩转Flowable流程实例 如何查询已经执行过的流程信息?
Flowable流程实例的挂起(暂停)与激活 如何使用流程中的DataObject并为流程设置租户 Flowable中ReceiveTask怎么玩?
Flowable设置任务处理人的四种方式 Flowable任务如何认领,回退? Flowable按角色分配任务
Flowable服务任务执行的三种方式 在Java代码中来一段JavaScript?聊聊Flowable中的脚本任务 体验一把Flowable三种常见网关
Flowable设置流程变量的四种方式 Flowable已经执行完毕的流程去哪找? Flowable定时器的各种玩法
Spring Boot + Flyway,自动化实现数据库版本控制 流程表单初体验 Flowable外置的HTML表单怎么玩?
使用JSON格式来定义Flowable外置表单 一图胜千言,实时掌握流程走到哪一步了 Flowable系列

springboot-freemarker

freemarker语法 poi-tl文档

springboot-i18n

一探究竟:深度解析Java国际化底层类ResourceBundle Spring Boot国际化踩坑指南

springboot-jasypt

两种方式,实现SpringBoot中数据库密码加密 Spring Boot保护敏感配置的4种方法 Spring Boot加密配置中的敏感信息
Springboot配置文件、隐私数据脱敏的最佳实践 Spring Boot配置文件这样加密,才足够安全! 仅需三步完成SpringBoot日志脱敏

springboot-kafka

consumer

# 消费者所属消费组的唯一标识
group.id
# 一次拉取请求的最大消息数,默认500条
max.poll.records
# 指定拉取消息线程最长空闲时间,默认300000ms
max.poll.interval.ms
# 检测消费者是否失效的超时时间,默认10000ms
session.timeout.ms
# 消费者心跳时间,默认3000ms
heartbeat.interval.ms
# 连接集群broker地址
bootstrap.servers
# 是否开启自动提交消费位移的功能,默认true
enable.auto.commit
# 自动提交消费位移的时间间隔,默认5000ms
auto.commit.interval.ms
# 消费者的分区配置策略,默认RangeAssignor
partition.assignment.strategy
# 如果分区没有初始偏移量,或者当前偏移量服务器上不存在时,将使用的偏移量设置,earliest从头开始消费,latest从最近的开始消费,none抛出异常,如果存在已经提交的offest时,不管设置为earliest或者latest都会从已经提交的offest处开始消费,如果不存在已经提交的offest时,earliest表示从头开始消费,latest表示从最新的数据消费,也就是新产生的数据.none topic各分区都存在已提交的offset时,从提交的offest处开始消费;只要有一个分区不存在已提交的offset,则抛出异常.kafka-0.10.1.X版本之前: auto.offset.reset的值为smallest,和,largest.(offest保存在zk中).kafka-0.10.1.X版本之后: auto.offset.reset的值更改为:earliest,latest,和none(offest保存在kafka的一个特殊的topic,名为:__consumer_offsets里面)
auto.offset.reset
# 消费者客户端一次请求从Kafka拉取消息的最小数据量,如果Kafka返回的数据量小于该值,会一直等待,直到满足这个配置大小,默认1b
fetch.min.bytes
# 消费者客户端一次请求从Kafka拉取消息的最大数据量,默认50MB
fetch.max.bytes
# 从Kafka拉取消息时,在不满足fetch.min.bytes条件时,等待的最大时间,默认500ms
fetch.max.wait.ms
# 强制刷新元数据时间,毫秒,默认300000,5分钟
metadata.max.age.ms
# 设置从每个分区里返回给消费者的最大数据量,区别于fetch.max.bytes,默认1MB
max.partition.fetch.bytes
# Socket发送缓冲区大小,默认128kb,-1将使用操作系统的设置
send.buffer.bytes
# Socket发送缓冲区大小,默认64kb,-1将使用操作系统的设置
receive.buffer.bytes
# 消费者客户端的id
client.id
# 连接失败后,尝试连接Kafka的时间间隔,默认50ms
reconnect.backoff.ms
# 尝试连接到Kafka,生产者客户端等待的最大时间,默认1000ms
reconnect.backoff.max.ms
# 消息发送失败重试时间间隔,默认100ms
retry.backoff.ms
# 样本计算时间窗口,默认30000ms
metrics.sample.window.ms
# 用于维护metrics的样本数量,默认2
metrics.num.samples
# metrics日志记录级别,默认info
metrics.log.level
# 类的列表,用于衡量指标,默认空list
metric.reporters
# 自动检查CRC32记录的消耗
check.crcs
# key反序列化方式
key.deserializer
# value反序列化方式
value.deserializer
# 设置多久之后关闭空闲连接,默认540000ms
connections.max.idle.ms
# 客户端将等待请求的响应的最大时间,如果在这个时间内没有收到响应,客户端将重发请求,超过重试次数将抛异常,默认30000ms
request.timeout.ms
# 设置消费者api超时时间,默认60000ms
default.api.timeout.ms
# 自定义拦截器
interceptor.classes
# 内部的主题:consumer_offsets和一transaction_state。该参数用来指定Kafka中的内部主题是否可以向消费者公开,默认值为true。如果设置为true,那么只能使用subscribe(Collection)的方式而不能使用subscribe(Pattern)的方式来订阅内部主题,设置为false则没有这个限制。
exclude.internal.topics
# 用来配置消费者的事务隔离级别。如果设置为“read committed”,那么消费者就会忽略事务未提交的消息,即只能消费到LSO(LastStableOffset)的位置,默认情况下为“read_uncommitted”,即可以消费到HW(High Watermark)处的位置
isolation.level
key.deserializer = org.apache.kafka.common.serialization.StringDeserializer
value.deserializer = org.apache.kafka.common.serialization.StringDeserializer

producer

# Snappy压缩技术是Google开发的,它可以在提供较好的压缩比的同时,减少对CPU的使用率并保证好的性能,所以建议在同时考虑性能和带宽的情况下使用。Gzip压缩技术通常会使用更多的CPU和时间,但会产生更好的压缩比,所以建议在网络带宽更受限制的情况下使用,默认不压缩,该参数可以设置成snappy、gzip或lz4对发送给broker的消息进行压缩
compression.type=Gzip
# 请求的最大字节数。这也是对最大消息大小的有效限制。注意:server具有自己对消息大小的限制,这些大小和这个设置不同。此项设置将会限制producer每次批量发送请求的数目,以防发出巨量的请求。
max.request.size=1048576
# TCP的接收缓存SO_RCVBUF空间大小,用于读取数据
receive.buffer.bytes=32768
# client等待请求响应的最大时间,如果在这个时间内没有收到响应,客户端将重发请求,超过重试次数发送失败
request.timeout.ms=30000
# TCP的发送缓存SO_SNDBUF空间大小,用于发送数据
send.buffer.bytes=131072
# 指定server等待来自followers的确认的最大时间,根据acks的设置,超时则返回error
timeout.ms=30000
# 在block前一个connection上允许最大未确认的requests数量。当设为1时,即是消息保证有序模式,注意:这里的消息保证有序是指对于单个Partition的消息有顺序,因此若要保证全局消息有序,可以只使用一个Partition,当然也会降低性能
max.in.flight.requests.per.connection=5
# 在第一次将数据发送到某topic时,需先fetch该topic的metadata,得知哪些服务器持有该topic的partition,该值为最长获取metadata时间
metadata.fetch.timeout.ms=60000
# 连接失败时,当我们重新连接时的等待时间
reconnect.backoff.ms=50
# 在重试发送失败的request前的等待时间,防止若目的Broker完全挂掉的情况下Producer一直陷入死循环发送,折中的方法
retry.backoff.ms=100
# metrics系统维护可配置的样本数量,在一个可修正的window size
metrics.sample.window.ms=30000
# 用于维护metrics的样本数
metrics.num.samples=2
# 类的列表,用于衡量指标。实现MetricReporter接口
metric.reporters=[]
# 强制刷新metadata的周期,即使leader没有变化
metadata.max.age.ms=300000
# 与broker会话协议,取值:LAINTEXT,SSL,SASL_PLAINTEXT,SASL_SSL
security.protocol=PLAINTEXT
# 分区类,实现Partitioner接口
partitioner.class=class org.apache.kafka.clients.producer.internals.DefaultPartitioner
# 控制block的时长,当buffer空间不够或者metadata丢失时产生block
max.block.ms=60000
# 关闭达到该时间的空闲连接
connections.max.idle.ms=540000
# 当向server发出请求时,这个字符串会发送给server,目的是能够追踪请求源
client.id=""
# acks=0配置适用于实现非常高的吞吐量,acks=all这是最安全的模式。Server完成producer request前需要确认的数量。acks=0时,producer不会等待确认,直接添加到socket等待发送;acks=1时,等待leader写到local log就行;acks=all或acks=-1时,等待isr中所有副本确认(注意:确认都是broker接收到消息放入内存就直接返回确认,不是需要等待数据写入磁盘后才返回确认,这也是kafka快的原因)
acks = all
# 发生错误时,重传次数。当开启重传时,需要将`max.in.flight.requests.per.connection`设置为1,否则可能导致失序
retries = 0
# 发送到同一个partition的消息会被先存储在batch中,该参数指定一个batch可以使用的内存大小,单位是byte。不一定需要等到batch被填满才能发送Producer可以将发往同一个Partition的数据做成一个Produce Request发送请求,即Batch批处理,以减少请求次数,该值即为每次批处理的大小。另外每个Request请求包含多个Batch,每个Batch对应一个Partition,且一个Request发送的目的Broker均为这些partition的leader副本。若将该值设为0,则不会进行批处理
batch.size = 16384
# 生产者在发送消息前等待linger.ms,从而等待更多的消息加入到batch中。如果batch被填满或者linger.ms达到上限,就把batch中的消息发送出去,Producer默认会把两次发送时间间隔内收集到的所有Requests进行一次聚合然后再发送,以此提高吞吐量,而linger.ms则更进一步,这个参数为每次发送增加一些delay,以此来聚合更多的Message。官网解释翻译:producer会将request传输之间到达的所有records聚合到一个批请求。通常这个值发生在欠负载情况下,record到达速度快于发送。但是在某些场景下,client即使在正常负载下也期望减少请求数量。这个设置就是如此,通过人工添加少量时延,而不是立马发送一个record,producer会等待所给的时延,以让其他records发送出去,这样就会被聚合在一起。这个类似于TCP的Nagle算法。该设置给了batch的时延上限:当我们获得一个partition的batch.size大小的records,就会立即发送出去,而不管该设置;但是如果对于这个partition没有累积到足够的record,会linger指定的时间等待更多的records出现。该设置的默认值为0(无时延)。例如,设置linger.ms=5,会减少request发送的数量,但是在无负载下会增加5ms的发送时延。
linger.ms = 1
# Producer可以用来缓存数据的内存大小。该值实际为RecordAccumulator类中的BufferPool,即Producer所管理的最大内存。如果数据产生速度大于向broker发送的速度,producer会阻塞max.block.ms,超时则抛出异常
buffer.memory = 33554432
key.serializer = org.apache.kafka.common.serialization.StringSerializer
value.serializer = org.apache.kafka.common.serialization.StringSerializer
Spring Kafka之@KafkaListener单条或批量处理消息 SpringBoot整合Kafka实现千万级数据异步处理,实战介绍!

springboot-lifecycle

Aware接口

每一个Aware的作用如下:

  • ApplicationEventPublisherAware:实现该接口的对象可以获取事件发布的能力。
  • ServletContextAware:实现该接口的对象可以获取到ServletContext对象。
  • MessageSourceAware:实现该接口的对象可以获取到MessageSource对象,MessageSource支持多消息源,主要用于主要用于国际化。
  • ResourceLoaderAware:实现该接口的对象可以获取到一个ResourceLoader,Spring ResourceLoader则为我们提供了一个统一的getResource()方法来通过资源路径检索外部资源,例如文本文件、XML文件、属性文件或图像文件等。
  • ApplicationStartupAware:实现该接口的对象可以获取到一个ApplicationStartup对象,这个比较新,是Spring5.3中新推出的,通过ApplicationStartup可以标记应用程序启动期间的步骤,并收集有关执行上下文或其处理时间的数据。
  • NotificationPublisherAware:实现该接的对象可以获取到一个NotificationPublisher对象,通过该对象可以实现通知的发送。
  • EnvironmentAware:实现该接口的对象可以获取到一个Environment对象,通过Environment可以获取到容器的环境信息。
  • BeanFactoryAware:实现该接口的对象可以获取到一个BeanFactory对象,通过BeanFactory可以完成Bean的查询等操作。
  • ImportAware:实现该接口的对象可以获取到一个AnnotationMetadata对象,ImportAware接口是需要和@Import注解一起使用的。在@Import作为元注解使用时,通过@Import导入的配置类如果实现了ImportAware接口就可以获取到导入该配置类接口的数据配置。
  • EmbeddedValueResolverAware:实现该接口的对象可以获取到一个StringValueResolver对象,通过StringValueResolver对象,可以读取到Spring容器中的properties配置的值(YAML配置也可以)。
  • ServletConfigAware:实现该接口的对象可以获取到一个ServletConfig对象,不过这个似乎没什么用,我们很少自己去配置ServletConfig。
  • LoadTimeWeaverAware:实现该接口的对象可以获取到一个LoadTimeWeaver对象,通过该对象可以获取加载Spring Bean时织入的第三方模块,如AspectJ等。
  • BeanClassLoaderAware:实现该接口的对象可以获取到一个ClassLoader对象。
  • BeanNameAware:实现该接口的对象可以获取到一个当前Bean的名称。
  • ApplicationContextAware:实现该接口的对象可以获取到一个ApplicationContext对象,通过-ApplicationContext可以获取容器中的Bean、环境等信息。

Spring Boot监听器

Spring Boot启动事件顺序ApplicationListener中的泛型的类型,可以在MyEvent里面实现某一个接口来监听不同的事件

  1. ApplicationStartingEvent
    这个事件在Spring Boot应用运行开始时,且进行任何处理之前发送(除了监听器和初始化器注册之外)。
  2. ApplicationEnvironmentPreparedEvent
    这个事件在当已知要在上下文中使用Spring环境(Environment)时,在Spring上下文(context)创建之前发送。
  3. ApplicationContextInitializedEvent
    这个事件在当Spring应用上下文(ApplicationContext)准备好了,并且应用初始化器(ApplicationContextInitializers)已经被调用,在bean的定义(bean definitions)被加载之前发送。
  4. ApplicationPreparedEvent
    这个事件是在Spring上下文(context)刷新之前,且在bean的定义(bean definitions)被加载之后发送。
  5. ApplicationStartedEvent
    这个事件是在Spring上下文(context)刷新之后,且在application/command-line runners被调用之前发送。
  6. AvailabilityChangeEvent
    这个事件紧随上个事件之后发送,状态:ReadinessState.CORRECT,表示应用已处于活动状态。
  7. ApplicationReadyEvent
    这个事件在任何application/ command-line runners调用之后发送。
  8. AvailabilityChangeEvent
    这个事件紧随上个事件之后发送,状态:ReadinessState.ACCEPTING_TRAFFIC,表示应用可以开始准备接收请求了。
  9. ApplicationFailedEvent
    这个事件在应用启动异常时进行发送

注册监听器方式1:
implements ApplicationListener<T>接口在类上增加@Component注册bean
自定义事件代码如下:

@Component
public class CustomListener implements ApplicationListener<MyEvent>{
    @Override
    public void onApplicationEvent(MyEvent myEvent) {
        myEvent.printMsg();
    }
}
@SuppressWarnings("serial")
public class MyEvent extends ApplicationEvent{
	public MyEvent(Object source){super(source);}
}

注册监听器方式2:
使用监听器的时候如果不将监听器的类注册为spring bean则使用这种方式添加

ConfigurableApplicationContext context = SpringApplication.run(XmxeApplication.class, args);
// 装载监听
context.addApplicationListener(new com.xmxe.config.listen.CustomListener());

注册监听器方式3:
application.properties中配置监听context.listener.classes=com.xmxe.config.listen.CustomListener

注册监听器方式4:
创建MyListener4类,该类无需实现ApplicationListener接口,使用@EventListener装饰具体方法

@Component
public class MyListener4{
	Logger logger = Logger.getLogger(MyListener4.class);
	@EventListener
    public void listener(MyEvent event){
    logger.info(String.format("%s监听到事件源:%s.", MyListener4.class.getName(), event.getSource()));}
}

// 进行测试(在启动类中加入发布事件的逻辑):
@SpringBootApplication
public class LisenterApplication{
	public static void main(String[] args){
		ConfigurableApplicationContext context = SpringApplication.run(LisenterApplication.class, args);
		//装载事件
		context.addApplicationListener(new MyListener1());
		//发布事件
		context.publishEvent(new MyEvent("测试事件."));}
}

ConfigurableApplicationContext方法

ConfigurableApplicationContext即为SpringApplication.run()返回值


static interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {

/**
 * 应用上下文配置时,这些符号用于分割多个配置路径
 */
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";

/**
 * BeanFactory中,ConversionService类所对应的bean的名字。如果没有此类的实例的话则使用默认的转换规则
 */
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";

/**
 * LoadTimeWaver类所对应的Bean在容器中的名字。如果提供了该实例,上下文会使用临时的ClassLoader,这样,LoadTimeWaver就可以使用bean确切的类型了
 */
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";

/**
 * Environment类在容器中实例的名字
 */
String ENVIRONMENT_BEAN_NAME = "environment";

/**
 * System系统变量在容器中对应的Bean的名字
 */
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";

/**
 * System环境变量在容器中对应的Bean的名字
 */
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";

/**
 * 设置容器的唯一ID
 */
void setId(String id);

/**
 * 设置此容器的父容器,需要注意的是,父容器一经设定就不应该修改。并且一般不会在构造方法中对其进行配置,因为很多时候其父容器还不可用。比如WebApplicationContext。
 */
void setParent(ApplicationContext parent);

/**
 * 设置容器的Environment变量
 */
void setEnvironment(ConfigurableEnvironment environment);

/**
 * 以COnfigurableEnvironment的形式返回此容器的环境变量。以使用户更好的进行配置
 */
@Override
ConfigurableEnvironment getEnvironment();

/**
 * 此方法一般在读取应用上下文配置的时候调用,用以向此容器中增加BeanFactoryPostProcessor。增加的Processor会在容器refresh的时候使用。
 */
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);

/**
 * 向容器增加一个ApplicationListener,增加的Listener用于发布上下文事件如refresh和shutdown等,需要注意的是,如果此上下文还没有启动,那么在此注册的Listener将会在上下文refresh的时候,全部被调用,如果上下文已经是active状态的了,就会在multicaster中使用
*/
void addApplicationListener(ApplicationListener<?> listener);

/**
 * 向容器中注入给定的Protocol resolver,允许多个实例同时存在。在此注册的每一个resolver都将会在上下的标准解析规则之前使用。因此,某种程度上来说这里注册的resolver可以覆盖上下文的resolver
 */
void addProtocolResolver(ProtocolResolver resolver);

/**
 * 加载资源配置文件(XML、properties,Whatever)。由于此方法是一个初始化方法,因此如果调用此方法失败的情况下,要将其已经创建的Bean销毁。换句话说,调用此方法以后,要么所有的Bean都实例化好了,要么就一个都没有实例化
 */
void refresh() throws BeansException, IllegalStateException;

/**
 * 向JVM注册一个回调函数,用以在JVM关闭时,销毁此应用上下文。
 */
void registerShutdownHook();

/**
 * 关闭此应用上下文,释放其所占有的所有资源和锁。并销毁其所有创建好的singleton Beans,实现的时候,此方法不应该调用其父上下文的close方法,因为其父上下文具有自己独立的生命周期.多次调用此方法,除了第一次,后面的调用应该被忽略。
 */
@Override
void close();

/**
 * 检测此FactoryBean是否被启动过。
 */
boolean isActive();

/**
 * 返回此应用上下文的容器。千万不要使用此方法来对BeanFactory生成的Bean做后置处理,因为单例Bean在此之前已经生成,这种情况下应该使用BeanFactoryPostProcessor来在Bean生成之前对其进行处理。通常情况下,内容容器只有在上下文是激活的情况下才能使用。因此,在使用此方法前,可以调用isActive来判断容器是否可用
 */
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

}

相关文章

SpringBoot 优雅停机的正确姿势 Spring Boot自定义监听事件 Spring Boot如何使用拦截器、过滤器、监听器?
Spring Boot过滤器、拦截器、监听器对比及使用场景 手把手教你在SpringBoot中自定义参数解析器 SpringBoot初始化几大招式,看了终于明白了
Spring Boot中如何统一API接口响应格式?–HandlerMethodReturnValueHandler 如何优雅记录HTTP请求/响应数据? 聊聊Spring中最常用的11个扩展点
16个有用的SpringBoot扩展接口 HandlerMethod Spring MVC中处理Request和Response的策略
Spring中的@EventListener注解

springboot-starter

spring.factory在spring boot3.0移除的解决办法

如果你有探索过这些Starter的原理,那你一定知道Spring Boot并没有消灭这些原本你要配置的Bean,而是将这些Bean做成了一些默认的配置类,同时利用/META-INF/spring.factories这个文件来指定要加载的默认配置。这样当Spring Boot应用启动的时候,就会根据引入的各种Starter中的/META-INF/spring.factories文件所指定的配置类去加载Bean。而Spring Boot 2.7中,有一个不推荐使用的内容就是关于这个/META-INF/spring.factories文件的,在Spring Boot 3开始将移除对/META-INF/spring.factories的支持。
img

那么具体怎么改呢?下面以之前我们编写的一个swagger的starter为例,它的/META-INF/spring.factories内容是这样的:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.spring4all.swagger.SwaggerAutoConfiguration

我们只需要创建一个新的文件:/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,内容的话只需要直接放配置类就可以了,比如这样:

com.spring4all.swagger.SwaggerAutoConfiguration

注意:这里多了一级spring目录。
如果你觉得维护这个太麻烦的话,还可以使用mica-auto来让他自动生成,具体怎么用可以看之前发的这篇文章

文章

如何优雅的实现Spring Boot接口参数加密解密? SpringBoot接口层统一加密解密 Spring Boot接口数据加解密技巧
不管是spring.factories还是最新的imports文件,这个神器帮你全自动生成! spring-boot-starter-swagger 图文并茂,Spring Boot Starter万字详解!还有谁不会?
五分钟说清楚Spring Boot的自动配置原理 Spring Boot自动装配原理,这一篇就够了! Tomcat在SpringBoot中是如何启动的?
手把手带你剖析Springboot启动原理! 一个注解,搞定SpringBoot自动化启动 SpringBoot自动装配的原理分析
SpringBoot自动装配原理 一文看懂SpringBoot启动流程!

springboot-state-machine

项目终于用上了Spring状态机,非常优雅! mybatis-plus文档 mybatis-plus-samples

springboot-upload

Spring Boot项目超大文件上传时,如何实现秒传? 大文件上传下载实现思路,分片、断点续传代码实现 Spring Boot多线程异步上传图片、处理水印、缩略图
Spring Boot分片上传、断点续传、大文件极速秒传 Spring Boot实现文件断点下载,实战来了!

springboot-websocket

WebSocket分布式集群怎么搞? 聊聊分布式WebSocket集群解决方案 Spring Boot + Netty + WebSocket实现消息推送
Spring Boot+Netty+Websocket实现后台向前端推送信息 Spring Boot + Web Socket打造实时监控异常 实现web实时消息推送的方案,7种!
Spring Boot整合Socket实战案例,实现单点发送、广播群发,1对1,1对多 基于ChatGPT API和WebSocket的实时机器人聊天应用 实现web实时消息推送的方案总结
Spring Boot整合Socket实战案例,实现单点发送、广播群发,1对1,1对多 WebSocket的6种集成方式 万字详解,带你彻底掌握WebSocket用法
Spring Boot + WebSocket实现实时通知功能 你还在使用websocket实现实时消息推送吗?(SSE使用)

SpringBoot

SpringApplication.run()(3.0版本)

// SpringApplication构造方法
new SpringApplication(Application.class){
    this((ResourceLoader)null, primarySources);
}
// 创建一个新的实例,这个应用程序的上下文将要从指定的来源加载Bean
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 资源初始化资源加载器,默认为null
    this.resourceLoader = resourceLoader;
    // 断言主要加载资源类不能为null,否则报错
    Assert.notNull(primarySources, "PrimarySources must not be null");
    // 初始化主要加载资源类集合并去重
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 推断当前 WEB 应用类型,一共有三种:NONE(非web项目),SERVLET(servlet web项目),REACTIVE(响应式web项目)
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 设置应用上线文初始化器,从"META-INF/spring.factories"读取ApplicationContextInitializer类的实例名称集合并去重,并进行set去重。(一共7个)
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 设置监听器,从"META-INF/spring.factories"读取ApplicationListener类的实例名称集合并去重,并进行set去重。(一共11个)
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 推断主入口应用类,通过当前调用栈,获取Main方法所在类,并赋值给mainApplicationClass
    this.mainApplicationClass = deduceMainApplicationClass();
    }

// run()方法
public ConfigurableApplicationContext run(String... args) {
    long startTime = System.nanoTime();
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    this.configureHeadlessProperty();
    // 创建所有spring运行监听器并发布应用启动事件,加载所有SpringApplicationRunListener的实现类
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 调用了starting
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    try {
        // 创建ApplicationArguments对象,获取应用程序启动参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 根据运行监听器和应用参数来准备spring环境,自定义监听器加载配置信息和系统环境变量,调用了environmentPrepared
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        Banner printedBanner = printBanner(environment);
        // 创建Spring上下文并加载Bean
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        // 准备ApplicationContext,该步骤包含一个非常关键的操作,将启动类注入容器,为后续开启自动化提供基础,内部调用了contextPrepared、contextLoaded
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        // 刷新应用上下文(自动装配,初始化IOC容器)
        this.refreshContext(context);
        // 应用上下文刷新后置处理,做一些扩展功能
        this.afterRefresh(context, applicationArguments);
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
        }
 		// 执行所有的Runner运行器,调用了started
        listeners.started(context, timeTakenToStartup);
        // 执行所有的Runner运行器
        callRunners(context, applicationArguments);
    } catch (Throwable var12) {
        if (var12 instanceof AbandonedRunException) {
            throw var12;
        }
 		// 内部调用了failed
        this.handleRunFailure(context, var12, listeners);
        throw new IllegalStateException(var12);
    }

    try {
        if (context.isRunning()) {
            Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
             // 发布应用上下文就绪事件,调用了reday
            listeners.ready(context, timeTakenToReady);
        }
		// 返回应用上下文
        return context;
    } catch (Throwable var11) {
        if (var11 instanceof AbandonedRunException) {
            throw var11;
        } else {
            this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var11);
        }
    }
}

public interface SpringApplicationRunListener {
    // run方法第一次被执行时调用,早期初始化工作
    void starting();
    // environment创建后,ApplicationContext创建前
    void environmentPrepared(ConfigurableEnvironment environment);
    // ApplicationContext实例创建,部分属性设置了
    void contextPrepared(ConfigurableApplicationContext context);
    // ApplicationContext加载后,refresh前
    void contextLoaded(ConfigurableApplicationContext context);
    // refresh后
    void started(ConfigurableApplicationContext context);
    // 所有初始化完成后,run结束前
    void running(ConfigurableApplicationContext context);
    // 初始化失败后
    void failed(ConfigurableApplicationContext context, Throwable exception);
}

Spring MVC配置相关

Spring Boot中,SpringMVC相关的自动化配置是在WebMvcAutoConfiguration配置类中实现的,它的生效条件有一条,就是当不存在WebMvcConfigurationSupport的实例时,这个自动化配置才会生生效。因此,如果我们在Spring Boot中自定义SpringMVC配置时选择了继承WebMvcConfigurationSupport,就会导致Spring Boot中SpringMVC的自动化配置失效。Spring Boot给我们提供了很多自动化配置,很多时候当我们修改这些配置的时候,并不是要全盘否定Spring Boot提供的自动化配置,我们可能只是针对某一个配置做出修改,其他的配置还是按照Spring Boot默认的自动化配置来,而继承WebMvcConfigurationSupport来实现对SpringMVC的配置会导致所有的SpringMVC自动化配置失效,因此,一般情况下我们不选择这种方案。

若直接继承WebMvcConfigurationSupport,会导致application.properties配置文件不生效,需要增加以下等相关配置代替配置文件
例:

@Bean
public InternalResourceViewResolver resourceViewResolver(){
    InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
    // 请求视图文件的前缀地址
    internalResourceViewResolver.setPrefix("/WEB-INF/views/");
    // 请求视图文件的后缀
    internalResourceViewResolver.setSuffix(".jsp");
    return internalResourceViewResolver;
}

@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
    super.configureViewResolvers(registry);
    registry.viewResolver(resourceViewResolver());
    registry.jsp("/WEB-INF/views/",".jsp");
}

在SpringBoot2.0及Spring 5.0WebMvcConfigurerAdapter已被废弃,标记为过时。使用方式:

  1. 直接实现WebMvcConfigurer(官方推荐)WebMvcConfigurer详解
  2. 直接继承WebMvcConfigurationSupport(继承此方法会导致application.properties不生效)
// WebMvcConfigurer常用的方法 
// 解决跨域问题 
public void addCorsMappings(CorsRegistry registry) ;
// 添加拦截器
void addInterceptors(InterceptorRegistry registry);
// 这里配置视图解析器 
void configureViewResolvers(ViewResolverRegistry registry);
// 配置内容裁决的一些选项
void configureContentNegotiation(ContentNegotiationConfigurer configurer);
// 视图跳转控制器 
void addViewControllers(ViewControllerRegistry registry);
// 静态资源处理 
void addResourceHandlers(ResourceHandlerRegistry registry);
// 默认静态资源处理器
void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);

跟自定义SpringMVC相关的类和注解主要有如下四个:

  • WebMvcConfigurerAdapter
  • WebMvcConfigurer
  • WebMvcConfigurationSupport
  • @EnableWebMvc

Spring Boot1.x中,自定义SpringMVC配置可以通过继承WebMvcConfigurerAdapter来实现。
Spring Boot2.x中,自定义SpringMVC配置可以通过实现WebMvcConfigurer接口来完成。
如果在Spring Boot中使用继承WebMvcConfigurationSupport来实现自定义SpringMVC配置,或者在Spring Boot中使用了@EnableWebMvc注解,都会导致Spring Boot中默认的SpringMVC自动化配置失效。在纯Java配置的SSM环境中,如果我们要自定义SpringMVC配置,有两种办法,第一种就是直接继承自WebMvcConfigurationSupport来完成SpringMVC配置,还有一种方案就是实现WebMvcConfigurer接口来完成自定义SpringMVC配置,如果使用第二种方式,则需要给SpringMVC的配置类上额外添加@EnableWebMvc注解,表示启用WebMvcConfigurationSupport,这样配置才会生效。换句话说,在纯Java配置的SSM中,如果你需要自定义SpringMVC配置,你离不开WebMvcConfigurationSupport,所以在这种情况下建议通过继承WebMvcConfigurationSupport来实现自动化配置。

扫描注解

  1. implements SmartInitializingSingleton
String[] beanDefinitionsNames=applicationContext.getBeanNamesForType(LifeCycleController.class,false,true);
for (String beanDefinitionName : beanDefinitionsNames){
	Object bean = applicationContext.getBean(beanDefinitionName);
    // map = 注解及注解所在的方法
    Map<Method, InvokeMethod> annotatedMethods = null;
    try{
        // 查找bean里指定注解的方法
        annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(), new MethodIntrospector.MetadataLookup<InvokeMethod>() {
            @Override
            public InvokeMethod inspect(Method method) {
                return AnnotatedElementUtils.findMergedAnnotation(method,InvokeMethod.class);
            }
        });
    }catch (Exception e){
        e.printStackTrace();
    }
  1. implements BeanPostProcessor
Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());
for (Method method : methods) {
    MsgEvent myMsgEvent = AnnotationUtils.findAnnotation(method, MsgEvent.class)
}
  1. HandlerMethod.getMethodAnnotation(Class<A> annotationType),底层AnnotatedElementUtils.findMergedAnnotation(method,InvokeMethod.class)实现

  2. HandlerMethodSelector在spring5.0中废弃

    Class<?> handlerType = applicationContext.getType(beanName);
    final Class<?> userType = ClassUtils.getUserClass(handlerType);
    Set<Method> = HandlerMethodSelector.selectMethods(userType, new ReflectionUtils.MethodFilter() {
    	public boolean matches(Method method) {
        	OpanApi methodAnnotation = AnnotationUtils.findAnnotation(method, OpanApi.class);
            if (methodAnnotation != null) {
                return true;
            }
            return false;
        }
    });
    

相关文章

Spring Boot核心知识剖析,写得太好了 为什么SpringBoot的jar可以直接运行? Spring Boot为何可以使用Jar包启动?
Spring Boot手动配置@Enable的秘密 Spring Boot源码分析(2.1.0.RELEASE) Spring Boot相关漏洞学习资料
springboot源码解析(一):启动过程 3分钟了解SpringBoot的启动流程 Spring Boot面试:说说自动配置的原理?
Spring Boot启动注解分析 SpringBoot启动原理详解(图文全面总结) 如何加快Spring Boot启动速度?

springcloud-config

springcloud-config-server

客户端通过直接调用配置中心的server端来获取配置文件信息。但是存在了一个问题,客户端和服务端的耦合性太高,如果server端要做集群,客户端只能通过原始的方式来路由,server端改变IP地址的时候,客户端也需要修改配置,不符合springcloud服务治理的理念。
springcloud提供了这样的解决方案,我们只需要将server端当做一个服务注册到eureka中,client端去eureka中去获取配置中心server端的服务既可。与之前配置相比主要是去掉了spring.cloud.config.uri直接指向server端地址的配置,增加了最后的三个配置:

  1. spring.cloud.config.discovery.enabled :开启Config服务发现支持
  2. spring.cloud.config.discovery.serviceId :指定server端的name,也就是server端spring.application.name的值
  3. eureka.client.serviceUrl.defaultZone :指向注册中心的地址

config server集成spring-cloud-starter-bus-kafka和spring-boot-starter-actuator
在远程仓库修改配置文件的时候通过 http://config-server:port/actuator/bus-refresh 来刷新所有springcloud-config-client,无须重启springcloud-config-client,也无须在springcloud-config-client上一个一个单独通过 http://configclientID:port/actuator/refresh 来刷新config-client的数据。
借助Git仓库的WebHook,我们就可轻松实现配置的自动刷新

Nacos、Apollo、Config配置中心如何选型

springcloud-consul

Consul下载 Consul文档 Consul Github

springcloud-gateway

微服务为什么要使用网关

不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:

  1. 客户端会多次请求不同的微服务,增加了客户端的复杂性
  2. 存在跨域请求,在一定场景下处理相对复杂
  3. 认证复杂,每个服务都需要独立认证
  4. 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施
  5. 某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难
    以上这些问题可以借助网关解决。

微服务网关的优点

  1. 安全 ,只有网关系统对外进行暴露,微服务可以隐藏在内网,通过防火墙保护。
  2. 易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
  3. 易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
  4. 减少了客户端与各个微服务之间的交互次数
  5. 易于统一授权。
  6. 网关的作用:转发功能,熔断功能,限流功能

文章

网关系统就该这么设计(万能通用) 为什么我们的微服务中需要网关? Spring Cloud 微服务网关Gateway使用详解
Spring Cloud Gateway在微服务架构下的最佳实践

springcloud-openfeign

Feign调用常见问题避坑指南!

springcloud-shenyu

GitHub ShenYu Apache ShenYu文档 ShenYu Admin\BootStrap二进制包下载地址(不使用源码启动的话直接下载包启动)

springcloud-tencent

北极星官网 北极星下载地址

SpringCloud

Spring Cloud与Spring Boot版本对比 Spring Cloud Alibaba版本说明 Spring Cloud Tencent版本管理
Spring Cloud–GitHub Spring Cloud中文网 一份微服务架构手稿图,彻底搞定微服务核心原理!
1.5W字搞懂Spring Cloud,太牛了! 微服务三十三问,两万字图文详解! 把Spring Cloud给拆了!详解每个组件的作用
Spring Cloud使用@RefreshScope注解配置动态刷新 Spring Cloud轻松解决跨域,别再乱用了

文章作者: xmxe
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 xmxe !
 上一篇
MyBatis相关 MyBatis相关
缓存一级缓存是默认开启的,它在一个sqlSession会话里面的所有查询操作都会保存到缓存中,一般来说一个请求中的所有增删改查操作都是在同一个sqlSession里面的,所以我们可以认为每个请求都有自己的一级缓存,如果同一个sqlSessi
下一篇 
Flash Flash,Hundred Yard Dash Flash Flash,Hundred Yard Dash
下载 apache旗下安装包 centos rpm包(cat /etc/centos-release) PLSQL历史版本下载 Clash下载 / GitHub Clash Meta for Andr
  目录