案例解析:springboot自动配置未生效问题定位(条件断点)
Spring Boot在为开发人员提供更高层次的封装,进而提高开发效率的同时,也为出现问题时如何进行定位带来了一定复杂性与难度。但Spring Boot同时又提供了一些诊断工具来辅助开发与分析,如spring-boot-starter-actuator。本文分享一个基于actuator与IDEA条件断点来定位自动配置未生效的案例。望对类似问题分析与处理提供参考。
欢迎关注我的微信公众号:jboost-ksxy
问题确认
在前文介绍的 Spring Boot从入门到实战:整合通用Mapper简化单表操作 中,我们对druid连接池做了自动配置,并且注入了druid的监控统计功能,如下

但本地运行后通过 http://localhost:8080/druid/index.html 访问时却出现错误,通过浏览器的开发者工具查看该请求返回404,推测上述代码中定义的StatViewServlet未注入成功。我们用actuator来确认下是否如此。在项目中加入spring-boot-starter-actuator,并且application.yml中添加如下配置
management:
endpoints:
web:
exposure:
include: "*"
exclude: beans,trace
endpoint:
health:
show-details: always
在spring-boot 2.x 版本当中,作为安全性考虑,将actuator 控件中的端口,只默认开放/health 和/info 两个端口,其他端口默认关闭, 因此需要添加如上配置。注意include的值
*必须加引号,否则无法启动。
重启程序后访问 http://localhost:8080/actuator/conditions 确认上述两个实例化方法未满足@ConditionalOnProperty的条件,从而未执行生效,如图

条件断点
从上面分析确认是因为条件注解 @ConditionalOnProperty(prefix = "spring.datasource.druid", name = "druidServletSettings") 未满足使方法未执行导致。那这个条件为什么没有满足呢,查看application.yml中也做了 spring.datasource.druid.druidServletSettings属性的配置。
当你无法理清头绪,确定问题原因时,那就Debug吧。查看注解@ConditionalOnProperty源码,找到其实现支持类OnPropertyCondition,如下
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({OnPropertyCondition.class})
public @interface ConditionalOnProperty {
String[] value() default {}; String prefix() default ""; String[] name() default {}; String havingValue() default ""; boolean matchIfMissing() default false;
}
查看OnPropertyCondition源码,了解它是通过getMatchOutcome方法来判断是否满足注解参数所指定的条件的,如下所示
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
metadata.getAllAnnotationAttributes(
ConditionalOnProperty.class.getName()));
List<ConditionMessage> noMatch = new ArrayList<>();
List<ConditionMessage> match = new ArrayList<>();
for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
ConditionOutcome outcome = determineOutcome(annotationAttributes,
context.getEnvironment());
(outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage());
}
if (!noMatch.isEmpty()) {
return ConditionOutcome.noMatch(ConditionMessage.of(noMatch));
}
return ConditionOutcome.match(ConditionMessage.of(match));
}
在调用determineOutcome处打断点,调试什么原因导致条件未满足,但是这里是一个for循环,如果for元素过多的话,将可能需要断点阻断很多次才能找到你想要查看的那个元素。所幸IDEA提供了不同类型的断点来处理这类问题,前面 案例解析:使用IDEA异常断点来定位java.lang.ArrayStoreException的问题 我们介绍了异常断点的使用。这里介绍用条件断点来处理这类循环块中的debug问题。
在上述代码for循环中调用determineOutcome行打断点,并在断点上右键,弹出如下窗口

图中Condition框即可输入你要指定的条件,可以直接写java判断表达式代码,并引用该行代码处能访问的变量,如这里我们输入 annotationAttributes.get("name").equals("druidServletSettings"),然后点击Debug窗口的“Resume Program (F9)”按钮,则在不满足指定条件时,断点处将不会被阻断,直到条件满足,这样就能很容易定位到我们想要查看的元素。(当然这里allAnnotationAttributes变量其实只有一个元素,仅仅是为了演示条件变量的使用,当集合元素很多时,使用条件断点就能体会到它的方便之处)
问题定位
通过Debug的方式深入条件注解的判断逻辑(其中循环处可使用条件断点),最终来到如下代码片段

在这里是判断来自所有属性源配置的属性中,是否包含条件注解指定的属性,即spring.datasource.druid.druidServletSettings,由上图可见,spring.datasource.druid.druidServletSettings只是某些属性的前缀,并不存在完全匹配的属性,因此返回false,导致条件不满足。回看注解@ConditionOnProperty的javadoc,
* If the property is not contained in the {@link Environment} at all, the
* {@link #matchIfMissing()} attribute is consulted. By default missing attributes do not
* match.
* <p>
* This condition cannot be reliably used for matching collection properties. For example,
* in the following configuration, the condition matches if {@code spring.example.values}
* is present in the {@link Environment} but does not match if
* {@code spring.example.values[0]} is present.
*
当Environment中不包含该属性时,则看matchIfMissing的值,该值默认为false,如果包含该属性,则再对比属性值与havingValue的值,相等即满足,不等则不满足。并且该条件注解不能用于匹配集合类型属性。上述spring.datasource.druid.druidServletSettings实际上属于一个Map类型,因此不能想当然地认为该注解是只要属性集中某属性名称包含该值即满足。
总结
当难以定位到问题原因时,可以进行Debug,跟踪程序运行的各个步骤,当要在循环中Debug定位到某个元素时,可以用条件断点来实现。@ConditionalOnProperty注解不是存在某属性就行,还需要值相等,并且不适用于集合类型属性。
我的个人博客地址:http://blog.jboost.cn
我的github地址:https://github.com/ronwxy
我的微信公众号:jboost-ksxy
———————————————————————————————————————————————————————————————

欢迎关注我的微信公众号,及时获取最新分享
案例解析:springboot自动配置未生效问题定位(条件断点)的更多相关文章
- 小BUG大原理:重写WebMvcConfigurationSupport后SpringBoot自动配置失效
一.背景 公司的项目前段时间发版上线后,测试反馈用户的批量删除功能报错.正常情况下看起来应该是个小 BUG,可怪就怪在上个版本正常,且此次发版未涉及用户功能的改动.因为这个看似小 BUG 我了解到不少 ...
- 小BUG大原理 | 第一篇:重写WebMvcConfigurationSupport后SpringBoot自动配置失效
一.背景 公司的项目前段时间发版上线后,测试反馈用户的批量删除功能报错.正常情况下看起来应该是个小BUG,可怪就怪在上个版本正常,且此次发版未涉及用户功能的改动.因为这个看似小BUG我了解到不少未知的 ...
- SpringBoot自动配置注解原理解析
1. SpringBoot启动主程序类: @SpringBootApplication public class DemoApplication { public static void main(S ...
- springboot自动配置源码解析
springboot版本:2.1.6.RELEASE SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfig ...
- SpringBoot 系列教程自动配置选择生效
191214-SpringBoot 系列教程自动配置选择生效 写了这么久的 Spring 系列博文,发现了一个问题,之前所有的文章都是围绕的让一个东西生效:那么有没有反其道而行之的呢? 我们知道可以通 ...
- SpringBoot自动配置探究
@SpringBootApplication @SpringBootApplication表示SpringBoot应用,标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就 ...
- 如何编写Spring-Boot自动配置
摘要 本文主要介绍如何把一个spring的项目(特别是一些公共工具类项目),基于spring boot的自动配置的思想封装起来,使其他Spring-Boot项目引入后能够进行快速配置. AutoCon ...
- SpringBoot实战之SpringBoot自动配置原理
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...
- 源码学习系列之SpringBoot自动配置(篇一)
源码学习系列之SpringBoot自动配置源码学习(篇一) ok,本博客尝试跟一下Springboot的自动配置源码,做一下笔记记录,自动配置是Springboot的一个很关键的特性,也容易被忽略的属 ...
随机推荐
- linux下仅仅有rman备份集的异机不同文件夹恢复
昨天在客户那里做了一次rman异机的恢复,把生产库弄一份给測试库用,总库大概80G,总共花费了2个小时,当时客户的环境是windows 11.2.0.3,今天早晨在linux下又一次測试了一下,记录下 ...
- WPF--3Dmax+blend+WPF综合运用
引自:http://blog.sina.com.cn/s/blog_95dbdf9e0100we3z.html 本人小菜,WPF刚入门,只是写一下最近的项目心得.欢迎各位前辈们前来拍砖指正,感激不敬! ...
- uwp - ContentDialog - 自定义仿iphone提示框,提示框美化
原文:uwp - ContentDialog - 自定义仿iphone提示框,提示框美化 为了实现我想要的效果花费了我很长时间,唉,当初英语不好好学,翻官网翻了半天才找到,分享给刚入门的新手. 首先看 ...
- DDD实战3 领域层的设计
1.新建一个解决方案文件夹 取名Product 2.在Product解决方案文件夹下面创建一个.net core 类库项目 取名Product.Domain,引用项目DDD.Base项目 3.在类库下 ...
- HTML 基础知识(特殊字符的转义)
1. body.head(meta) <body></body>标签的常见属性: bgcolor:整个页面的背景: text:设置文本颜色 link:设置连接颜色(),vlin ...
- 使用CMD实现批量重命名[转]
关键字:cmd DOS 批处理 批量 重命名 作者:lifesinger地址:http://www.cnblogs.com/txw1958/archive/2012/12/24/cmd-batch-r ...
- 对于ado.net dataProvider的介绍
学习刘皓的 ADO.NET入门教程(二)了解.NET数据提供程序 而来 这篇文章很一般,主要是对dataProvider做了个简单的介绍.因为在该系列文章中提到,ado.net主要有两部分 dataP ...
- ./configure,make,make install的作用(configure一般用来生成 Makefile,相当于qmake)
这些都是典型的使用GNU的AUTOCONF和AUTOMAKE产生的程序的安装步骤. ./configure是用来检测你的安装平台的目标特征的.比如它会检测你是不是有CC或GCC,并不是需要CC或GCC ...
- asp .net 文件浏览功能
达到的目的是,发布站点后,在站点某个目录下的图片文件可以通过url访问 步骤 1.新建一个网站 注意,不要建立在需要较高访问权限的地方,不要建立空网站 如果是需要较高访问权限的目录,而IIS本身账号的 ...
- WPF编游戏系列 之五 数据绑定
原文:WPF编游戏系列 之五 数据绑定 在上一篇通过用户控件将重复使用的控件封装为一个控件组,大大减少了C#代码数量,本篇继续对该控件组进行数据绑定,节省为每个控件赋值的工作.对于数据绑 ...