SpringBoot MapperScan添加动态配置(占位符)

参考文章:https://www.jianshu.com/p/a0a317fd8c67

在对Mybatis自动扫描配置中,使用注解配置时,@MapperScan中的配置,通常配置如下:

@MapperScan(basePackages = {"com.aa.**.mapper","com.bb.**.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory")

不支持在yml或properties文件中动态配置。因为MapperScan注解功能的实现类MapperScannerRegistrar实现的是ImportBeanDefinitionRegistrar。在对@Configuration注解标记的类配置时,实现占位符功能的PropertyPlaceholderAutoConfiguration还没有开始加载。

MapperScannerRegistrard的核心代码如下:

 
  1. List<String> basePackages = new ArrayList();
  2. basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
  3. basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));
  4. basePackages.addAll((Collection)Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));
  5. scanner.registerFilters();
  6. scanner.doScan(StringUtils.toStringArray(basePackages));
 

从上图代码中可以看出,为了拓展支持占位符动态配置,只需把basePackages的加载改写即可。

1、参考MapperScannerRegistrard,实现 ImportBeanDefinitionRegistrar和ResourceLoaderAware两个接口

2、为了动态读取配置文件信息,需要引入Environment,所以实现EnvironmentAware接口

3、代码

MapperScannerRegistrar.java

 
  1. import org.mybatis.spring.mapper.ClassPathMapperScanner;
  2. import org.mybatis.spring.mapper.MapperFactoryBean;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.beans.BeanUtils;
  6. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
  7. import org.springframework.beans.factory.support.BeanNameGenerator;
  8. import org.springframework.context.EnvironmentAware;
  9. import org.springframework.context.ResourceLoaderAware;
  10. import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
  11. import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
  12. import org.springframework.core.annotation.AnnotationAttributes;
  13. import org.springframework.core.env.Environment;
  14. import org.springframework.core.io.ResourceLoader;
  15. import org.springframework.core.type.AnnotationMetadata;
  16. import org.springframework.util.ClassUtils;
  17. import org.springframework.util.StringUtils;
  18.  
  19. import java.lang.annotation.Annotation;
  20. import java.util.*;
  21. import java.util.stream.Collectors;
  22.  
  23. public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware,EnvironmentAware {
  24.  
  25. private Environment environment;
  26.  
  27. private ResourceLoader resourceLoader;
  28.  
  29. private static final Logger logger = LoggerFactory.getLogger(MapperScannerRegistrar. class);
  30.  
  31. @Override
  32. public void setEnvironment(Environment environment) {
  33. this.environment = environment;
  34. }
  35.  
  36. @Override
  37. public void setResourceLoader(ResourceLoader resourceLoader) {
  38. this.resourceLoader = resourceLoader;
  39. }
  40.  
  41. @Override
  42. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  43.  
  44. AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScanner.class.getName()));
  45. if (mapperScanAttrs != null) {
  46. this.registerBeanDefinitions(mapperScanAttrs, registry);
  47. }
  48. }
  49.  
  50. void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {
  51. ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
  52. Optional var10000 = Optional.ofNullable(this.resourceLoader);
  53. Objects.requireNonNull(scanner);
  54. Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
  55. if (!Annotation.class.equals(annotationClass)) {
  56. scanner.setAnnotationClass(annotationClass);
  57. }
  58.  
  59. Class<?> markerInterface = annoAttrs.getClass("markerInterface");
  60. if (!Class.class.equals(markerInterface)) {
  61. scanner.setMarkerInterface(markerInterface);
  62. }
  63.  
  64. Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
  65. if (!BeanNameGenerator.class.equals(generatorClass)) {
  66. scanner.setBeanNameGenerator((BeanNameGenerator) BeanUtils.instantiateClass(generatorClass));
  67. }
  68.  
  69. Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
  70. if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
  71. scanner.setMapperFactoryBeanClass(mapperFactoryBeanClass);
  72. }
  73.  
  74. scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
  75. scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
  76. List<String> basePackages = new ArrayList<String>();
  77. basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
  78. for (String pkg : annoAttrs.getStringArray("basePackages")) {
  79. if (StringUtils.hasText(pkg)) {
  80. String value = parsePlaceHolder(pkg);
  81. if(StringUtils.hasText(value)){
  82. List<String> valueList = Arrays.asList(value.split(","));
  83. for(String base : valueList){
  84. basePackages.add(base);
  85. }
  86. }
  87. }
  88. }
  89. basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));
  90. scanner.registerFilters();
  91. scanner.doScan(StringUtils.toStringArray(basePackages));
  92. }
  93.  
  94. private String parsePlaceHolder(String pro) {
  95. if (StringUtils.hasText(pro) && pro.contains(PropertySourcesPlaceholderConfigurer.DEFAULT_PLACEHOLDER_PREFIX)) {
  96. String value = environment.getProperty(pro.substring(2, pro.length() - 1));
  97.  
  98. if (logger.isDebugEnabled()) {
  99. logger.debug("find placeholder value " + value + " for key " + pro);
  100. }
  101.  
  102. if (null == value) {
  103. throw new IllegalArgumentException("property " + pro + " can not find!!!");
  104. }
  105. return value;
  106. }
  107. return pro;
  108. }
  109. }
 
MapperScanner.java
 
  1. import org.mybatis.spring.mapper.MapperFactoryBean;
  2. import org.springframework.beans.factory.support.BeanNameGenerator;
  3. import org.springframework.context.annotation.Import;
  4.  
  5. import java.lang.annotation.*;
  6.  
  7. @Retention(RetentionPolicy.RUNTIME)
  8. @Target({ElementType.TYPE})
  9. @Documented
  10. @Import({MapperScannerRegistrar.class})
  11. public @interface MapperScanner {
  12. String[] value() default {};
  13.  
  14. String[] basePackages() default {};
  15.  
  16. Class<?>[] basePackageClasses() default {};
  17.  
  18. Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
  19.  
  20. Class<? extends Annotation> annotationClass() default Annotation.class;
  21.  
  22. Class<?> markerInterface() default Class.class;
  23.  
  24. String sqlSessionTemplateRef() default "";
  25.  
  26. String sqlSessionFactoryRef() default "";
  27.  
  28. Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;
  29. }
 

4、使用MapperScanner,占位符扫描配置

@MapperScanner(basePackages = { "${mybatis.mapperScanner.basePackage}" }, sqlSessionFactoryRef = "sqlSessionFactory")
 
  1. mybatis:
  2. mapperScanner:
  3. basePackage: com.aa.**.mapper,com.bb.**.mapper
 

SpringBoot MapperScan添加动态配置(占位符)_mapperscan basepackages-CSDN博客

posted @ 2025-02-05 14:56  CharyGao  阅读(193)  评论(0)    收藏  举报