在写一些自动配置类的时候,有时候需要基于应用环境中的变量是否匹配或者类是否加载来决定该配置类是否被加载,或者再引入一些第三方star的时候,不确定某些配置类是否被加载,但是又不是特别好调试。
基于此写了一个判断该配置是否加载的工具类,如果没有被加载,则会打印其未被加载的原因。
@Component
public class SpringDebugTrace implements ApplicationContextAware {
private final Logger logger = LoggerFactory.getLogger(getClass());
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void printLogConditionalResult(Class<?> clazz) {
printLogConditionalResult(clazz.getName(), true);
}
public void printLogConditionalResult() {
final Map<String, ConditionEvaluationReport.ConditionAndOutcomes> conditionAndOutcomesBySource =
this.applicationContext.getBean(ConditionEvaluationReport.class).getConditionAndOutcomesBySource();
for (String key : conditionAndOutcomesBySource.keySet()) {
printLogConditionalResult(key, false);
}
}
public void printLogConditionalResult(String clazzName, boolean match) {
final Map<String, ConditionEvaluationReport.ConditionAndOutcomes> conditionAndOutcomesBySource =
this.applicationContext.getBean(ConditionEvaluationReport.class).getConditionAndOutcomesBySource();
if (!logConditionalReport(conditionAndOutcomesBySource, clazzName, match)) {
for (String key : conditionAndOutcomesBySource.keySet()) {
if (key.startsWith(clazzName)) {
logConditionalReport(conditionAndOutcomesBySource, key, match);
}
}
}
}
/**
* 打印条件匹配结果日志
*
* @param conditionAndOutcomesMap 结果源
* @param key 类名
* @param match 是否展示匹配上
* @return
*/
private boolean logConditionalReport(
Map<String, ConditionEvaluationReport.ConditionAndOutcomes> conditionAndOutcomesMap, String key,
boolean match) {
final ConditionEvaluationReport.ConditionAndOutcomes conditionAndOutcomes = conditionAndOutcomesMap.get(key);
if (conditionAndOutcomes != null) {
for (ConditionEvaluationReport.ConditionAndOutcome next : conditionAndOutcomes) {
final ConditionOutcome outcome = next.getOutcome();
if (match || !outcome.isMatch()) {
logger.info(" 调试条件类:[{}] 是否满足条件:{} , 结果:{}", key, outcome.isMatch(), outcome.getMessage());
}
}
return true;
}
return false;
}
/**
* 查找基于SPI加载的接口类
* @param clazz
* @param <T>
* @return
*/
public <T> List<T> getSpringFactories(Class<T> clazz) {
return SpringFactoriesLoader.loadFactories(clazz, this.applicationContext.getClassLoader());
}
}
使用方式:
// 注入该类
@Autowired
private SpringDebugTrace springDebugTrace;
// 调试某个配置类
springDebugTrace.printLogConditionalResult(ElasticsearchDataAutoConfiguration.class);
// @ConditionalOnProperty(prefix = "spring.lkx", name = "abc") ,上下文中没有配置
springDebugTrace.printLogConditionalResult(RestAutoConfiguration.class);
打印结果:
调试条件类:[org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration] 是否满足条件:false , 结果:@ConditionalOnClass did not find required class 'org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate'
调试条件类:[com.enjoy.spring.boot.example.bean.RestAutoConfiguration] 是否满足条件:false , 结果:@ConditionalOnProperty (spring.lkx.abc) did not find property 'abc'
这样你在需要加载某些配置类的时候,能够清楚知道没有被加载的原因。