Spring AOT处理阶段如何正常读取MybatisProperties配置
Spring AOT处理时无法读取MybatisProperties的mapperLocations配置
问题描述
在Spring AOT编译处理阶段,自定义的MybatisBeanFactoryInitializationAotContribution中注入MybatisProperties后,调用getMapperLocations()返回空值,无法获取application.yml中配置的mybatis.mapper-locations值,导致无法正确注册资源RuntimeHints。
相关代码与配置如下:
自定义AOT贡献类
public class MybatisBeanFactoryInitializationAotContribution implements BeanFactoryInitializationAotContribution { private final MybatisProperties mybatisProperties; public MybatisBeanFactoryInitializationAotContribution(MybatisProperties mybatisProperties) { this.mybatisProperties = mybatisProperties; } @Override public void applyTo(GenerationContext generationContext, BeanFactoryInitializationCode beanFactoryInitializationCode) { log.info("MybatisBeanFactoryInitializationAotContribution {}", mybatisProperties.getMapperLocations()); RuntimeHints hints = generationContext.getRuntimeHints(); String[] mapperLocations = mybatisProperties.getMapperLocations(); if (mapperLocations != null) { log.info("mapperLocations-{}", mapperLocations); Stream.of(mapperLocations).map(item -> item.replace("classpath:/", "")).forEach(hints.resources()::registerPattern); } } }
application.yml配置
mybatis: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl mapper-locations: classpath:/mapper/*.xml
原因分析
Spring AOT是编译期预处理机制,此时常规的@ConfigurationProperties自动绑定流程尚未完全执行。直接注入的MybatisProperties实例是通过默认构造函数创建的,并未完成与application.yml配置的绑定,因此所有属性都是默认值(比如mapperLocations默认返回null)。
解决方案
方案1:通过Environment手动绑定属性
绕过自动绑定的时机限制,直接从Environment中读取配置并手动绑定到MybatisProperties实例:
修改后的MybatisBeanFactoryInitializationAotContribution:
import org.springframework.boot.context.properties.bind.Binder; import org.springframework.core.env.Environment; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import java.util.Arrays; import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MybatisBeanFactoryInitializationAotContribution implements BeanFactoryInitializationAotContribution { private static final Logger log = LoggerFactory.getLogger(MybatisBeanFactoryInitializationAotContribution.class); @Override public void applyTo(GenerationContext generationContext, BeanFactoryInitializationCode beanFactoryInitializationCode) { // 从BeanFactory获取Environment ConfigurableListableBeanFactory beanFactory = generationContext.getBeanFactory(); Environment environment = beanFactory.getEnvironment(); // 手动绑定MybatisProperties MybatisProperties mybatisProperties = Binder.get(environment) .bind("mybatis", MybatisProperties.class) .orElse(new MybatisProperties()); log.info("MybatisBeanFactoryInitializationAotContribution mapperLocations: {}", Arrays.toString(mybatisProperties.getMapperLocations())); RuntimeHints hints = generationContext.getRuntimeHints(); String[] mapperLocations = mybatisProperties.getMapperLocations(); if (mapperLocations != null) { Stream.of(mapperLocations) .map(location -> location.replace("classpath:/", "")) .forEach(hints.resources()::registerPattern); } } }
方案2:确保MybatisProperties提前完成初始化
在注册AOT贡献类时,先从BeanFactory中获取并初始化MybatisProperties,触发属性绑定:
对应的AOT处理器类:
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; public class MybatisBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor { @Override public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { // 主动获取MybatisBean,触发属性绑定 MybatisProperties mybatisProperties = beanFactory.getBean(MybatisProperties.class); return new MybatisBeanFactoryInitializationAotContribution(mybatisProperties); } }
注意事项
- 确保application.yml等配置文件位于
src/main/resources目录下,编译时能被正确加载到classpath中。 - 若使用多环境配置,需在AOT编译时指定激活的环境(如通过
-Dspring.profiles.active=dev参数),确保读取到正确的配置。
内容的提问来源于stack exchange,提问作者Qeir Mr.钟
相关产品推荐
相关产品推荐

