SpringBoot 为MapperScan添加动态扫描(占位符)功能

来源:互联网 发布:mac表老化时间 编辑:程序博客网 时间:2024/05/21 13:57

SpringBootLean 是对springboot学习与研究项目,是根据实际项目的形式对进行配置与处理,欢迎star与fork。 
[oschina 地址] 
http://git.oschina.net/cmlbeliever/SpringBootLearning 
[github 地址] 
https://github.com/cmlbeliever/SpringBootLearning

在对Mybatis自动扫描配置中,使用注解配置时,我们只要在@MapperScan中配置我们需要扫描的Mapper位置,大部分情况下是满足需求的。通常配置如下:

@MapperScan(basePackages = { "com.cml.springboot.sample.db" }, sqlSessionFactoryRef = "sqlSessionFactory")
  • 1

这样MapperScannerRegistrar就会去扫描com.cml.springboot.sample.db包下所有Mapper对象。

但是如果遇到需要动态配置扫描包,就有点麻烦了。

因为MapperScan是无法支持spring占位符功能。因为MapperScan注解功能的实现类MapperScannerRegistrar实现的是ImportBeanDefinitionRegistrar。在对@Configuration注解标记的类配置时,实现占位符功能的PropertyPlaceholderAutoConfiguration还没有开始加载。

作为拓展,那我们就可以自定义MapperScanner,实现接口EnvironmentAware,来添加占位符功能。主要代码也是参照MapperScannerRegistrar,主要是将

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {    //...省略代码    List<String> basePackages = new ArrayList<String>();    for (String pkg : annoAttrs.getStringArray("value")) {      if (StringUtils.hasText(pkg)) {        basePackages.add(pkg);      }    }    for (String pkg : annoAttrs.getStringArray("basePackages")) {      if (StringUtils.hasText(pkg)) {        basePackages.add(pkg);      }    }    for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {      basePackages.add(ClassUtils.getPackageName(clazz));    }      //...省略代码  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

改成

@Override    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {           //...省略代码        List<String> basePackages = new ArrayList<String>();        for (String pkg : annoAttrs.getStringArray("value")) {            if (StringUtils.hasText(pkg)) {                basePackages.add(parsePlaceHolder(pkg));            }        }        for (String pkg : annoAttrs.getStringArray("basePackages")) {            if (StringUtils.hasText(pkg)) {                basePackages.add(parsePlaceHolder(pkg));            }        }        for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {            basePackages.add(ClassUtils.getPackageName(clazz));        }           //...省略代码    }        private String parsePlaceHolder(String pro) {        if (pro != null && pro.contains(PropertySourcesPlaceholderConfigurer.DEFAULT_PLACEHOLDER_PREFIX)) {            String value = env.getProperty(pro.substring(2, pro.length() - 1));            if (logger.isDebugEnabled()) {                logger.debug("find placeholder value " + value + " for key " + pro);            }            if (null == value) {                throw new IllegalArgumentException("property " + pro + " can not find!!!");            }            return value;        }        return pro;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

使用时,只需要使用我们自定义的MapperScanner,并且配置basePackages

@MapperScanner(basePackages = { "${db.mybatis.mapperScanner.basePackage}" }, sqlSessionFactoryRef = "sqlSessionFactory")
  • 1

经过以上步骤,MapperScanner占位符功能添加成功。

使用场景分析:

  • 不想在代码上写死路径,而是通过配置文件配置Mapper位置
  • 在SpringApplication启动时,动态配置。结合SpringBatch可以实现只扫描当前batch下的Mapper功能

例如使用代码动态设置扫描路径

SpringApplication application = new SpringApplication(BootApplication.class);        Map<String, Object> defaultProperties = new HashMap<>();        defaultProperties.put("db.mybatis.mapperScanner.basePackage", "com.cml.springboot.batch."+batchId);        application.setDefaultProperties(defaultProperties);        application.setWebEnvironment(true);        application.run(args);
原创粉丝点击