springboot自动配置没有生效的问题定位(条件断点)

Spring Boot在为开发人员提供更高层次的封装,进而提高开发效率的同时,也为出现问题时如何进行定位带来了一定复杂性与难度。但Spring Boot同时又提供了一些诊断工具来辅助开发与分析,如spring-boot-starter-actuator。本文分享一个基于actuator与IDEA条件断点来定位自动配置未生效的案例。望对类似问题分析与处理提供参考。

问题确认

在前文介绍的 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提供了不同类型的断点来处理这类问题,这里介绍用条件断点来处理这类循环块中的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注解不是存在某属性就行,还需要值相等,并且不适用于集合类型属性。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • SpringBoot深入理解之内置web容器及配置的总结

    前言 在学会基本运用SpringBoot同时,想必搭过SSH.SSM等开发框架的小伙伴都有疑惑,SpringBoot在spring的基础上做了些什么,使得使用SpringBoot搭建开发框架能如此简单,便捷,快速.本系列文章记录网罗博客.分析源码.结合微薄经验后的总结,以便日后翻阅自省. 正文 使用SpringBoot时,首先引人注意的便是其启动方式,我们熟知的web项目都是需要部署到服务容器上,例如tomcat.weblogic.widefly(以前叫JBoss),然后启动web容器真正运行我

  • SpringBoot自动配置的实现原理

    一.运行原理 Spring Boot的运行是由注解@EnableAutoConfiguration提供的. @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({EnableAutoConfigurationImportSelector.class}) public @interface EnableAuto

  • SpringBoot整合MyBatisPlus配置动态数据源的方法

    MybatisPlus特性 •无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 •损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作 •强大的 CRUD 操作:内置通用 Mapper.通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 •支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错 •支持多种数据库:支持 MySQL.MariaDB.Ora

  • springboot-mongodb的多数据源配置的方法步骤

    在日常工作中,我们可能需要连接多个MongoDB数据源,比如用户库user,日志库log.本章我们来记录连接多个数据源的步骤,以两个数据源为例,多个数据源类推. 1.pom.xml中引入mongodb的依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </d

  • 全面解析SpringBoot自动配置的实现原理

    之前一直在用SpringBoot框架,一直感觉SpringBoot框架自动配置的功能很强大,但是并没有明白它是怎么实现自动配置的,现在有空研究了一下,大概明白了SpringBoot框架是怎么实现自动配置的功能,我们编写一个最简单的自动配置功能,大概的总结一下. 一,配置属性类 其实就是值对象注入的方式去配置一些Spring常用的配置,我们编写一个最简单的配置对象. @ConfigurationProperties(prefix = "hello") //@Component //如果这

  • SpringBoot通过yml和xml文件配置日志输出方法

    SpringBoot中默认使用Logback进行日志输出,可以同时使用SpringBoot框架的配置文件application.yml或是通过logback的配置文件logback.xml进行配置. 通过application.yml配置 <?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"> <!--定义日志文件的存储地址 勿在 Lo

  • springboot自动配置没有生效的问题定位(条件断点)

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

  • SpringBoot 自动配置失效的解决方法

    目录 问题描述 @EnableConfigurationProperties 注解行为 配置有效,AutoTestConfiguration 未刷新 prefix-type @ConditionalOnProperty @ConditionalOnProperty match 逻辑 @ConditionalOnProperty skip 逻辑 总结 本文源自近期项目中遇到的问题, bug 总是出现在你自以为是的地方... 问题描述 下面是一个简单复现的代码片段,在你没有阅读完本文时,如果能做出正

  • SpringBoot自动配置之自定义starter的实现代码

    前言:前面已经介绍了自动配置的很多原理,现在我们着手自己定义一个starter. 需求:自定义redis-starter,要求当导入redis坐标后,SpringBoot自动创建Jedis的Bean.正式开始之前,我们可以查看Mybatis的起步依赖是如果实现自动配置的.我这里就省略了,大家根据之前的分析文章,自己看源码即可. 一.先创建一个SpringBoot工程redis-spring-boot-autoconfigure,该工程中添加jedis依赖,并且创建一个自动配置类RedisAuto

  • SpringBoot自动配置原理,你真的懂吗?(简单易懂)

    概述 上面博文(SpringBoot简介与快速搭建)我们简单的介绍了什么是SpringBoot,以及如何使用SpringBoot,但是我们对于SpringBoot的基本原理并没有介绍,这篇博文我们重点介绍SpringBoot是如何实现的自动配置. 依赖管理 在我们的pom文件中最核心的依赖就一个: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-star

  • springboot自动配置原理解析

    前言 小伙伴们都知道,现在市面上最流行的web开发框架就是springboot了,在springboot开始流行之前,我们都用的是strust2或者是springmvc框架来开发web应用,但是这两个框架都有一个特点就是配置非常的繁琐,要写一大堆的配置文件,spring在支持了注解开发之后稍微有些改观但有的时候还是会觉得比较麻烦,这个时候springboot就体现出了它的优势,springboot只需要一个properties或者yml文件就可以简化springmvc中在xml中需要配置的一大堆

  • 详解SpringBoot自动配置源码

    一.引导加载自动配置类 @SpringBootApplication注解相当于@SpringBootConfiguration.@EnableAutoConfiguration.@ComponentScan这三个注解的整合 @SpringBootConfiguration 这个注解也使用了@Configuration标注,代表当前是一个配置类 @ComponentScan 包扫描,指定扫描哪些注解 @EnableAutoConfiguration 这个注解也是一个合成注解 @AutoConfig

  • 深入浅析SpringBoot自动配置原理

    SpringBoot2.3.1版本源码 一.SpringBoot启动的时候加载主配置类,通过@EnableAutoConfiguration注解开启了自动配置功能 . 二.@EnableAutoConfiguration作用: 1. 点击该注解进入可以发现,它利用AutoConfigurationImportSelector.class 选择器给SpringBoot导入一些组件.导入哪些组件呢?可以点击选择器进入查看selectImports()方法的内容,该方法最终会返回一个configurati

  • SpringBoot自动配置原理详解

    目录 阅读收获 一.SpringBoot是什么 二.SpringBoot的特点 三.启动类 3.1 @SpringBootApplication 四.@EnableAutoConfiguration 4.1 @AutoConfigurationPackage 4.2  @Import({AutoConfigurationImportSelector.class}) 五.流程总结图 六.常用的Conditional注解 七.@Import支持导入的三种方式 阅读收获 理解SpringBoot自动配

  • SpringBoot自动配置原理分析

    目录 前言 一.启动类 1.1.@SpringBootConfiguration 1.2.@EnableAutoConfiguration 1.3.@ComponentScan 1.4.探究方向 二.@SpringBootConfiguration 三.@EnableAutoConfiguration 3.1.@AutoConfigurationPackage 3.2.@Import(AutoConfigurationImportSelector.class) 3.2.1.getCandidat

  • SpringBoot自动配置特点与原理详细分析

    目录 一.SpringBoot是什么 二.SpringBoot的特点(核心功能) 三.SpringBoot的自动配置原理 1. @SpringBootApplication 2. @SpringBootConfiguration 3. @EnableAutoConfiguration 4. @ComponentScan 四.核心原理图 五.常用的Conditional注解 一.SpringBoot是什么 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Sprin

随机推荐