SpringBoot实现MapperScan添加动态配置(占位符)
作者:BUse 发布时间:2023-11-26 05:08:06
MapperScan添加动态配置(占位符)
在对Mybatis自动扫描配置中,使用注解配置时,@MapperScan中的配置,通常配置如下:
@MapperScan(basePackages = {"com.aa.**.mapper","com.bb.**.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory")
不支持在yml或properties文件中动态配置。因为MapperScan注解功能的实现类MapperScannerRegistrar实现的是ImportBeanDefinitionRegistrar。在对@Configuration注解标记的类配置时,实现占位符功能的PropertyPlaceholderAutoConfiguration还没有开始加载。
MapperScannerRegistrard的核心代码如下
List<String> basePackages = new ArrayList();
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
从上面代码中可以看出
为了拓展支持占位符动态配置,只需把basePackages的加载改写即可。
1、参考MapperScannerRegistrard,实现 ImportBeanDefinitionRegistrar和ResourceLoaderAware两个接口
2、为了动态读取配置文件信息,需要引入Environment,所以实现EnvironmentAware接口
3、代码
MapperScannerRegistrar.java
import org.mybatis.spring.mapper.ClassPathMapperScanner;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.stream.Collectors;
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware,EnvironmentAware {
private Environment environment;
private ResourceLoader resourceLoader;
private static final Logger logger = LoggerFactory.getLogger(MapperScannerRegistrar. class);
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScanner.class.getName()));
if (mapperScanAttrs != null) {
this.registerBeanDefinitions(mapperScanAttrs, registry);
}
}
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
Optional var10000 = Optional.ofNullable(this.resourceLoader);
Objects.requireNonNull(scanner);
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
scanner.setAnnotationClass(annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
scanner.setMarkerInterface(markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator((BeanNameGenerator) BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
scanner.setMapperFactoryBeanClass(mapperFactoryBeanClass);
}
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
List<String> basePackages = new ArrayList<String>();
basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
for (String pkg : annoAttrs.getStringArray("basePackages")) {
if (StringUtils.hasText(pkg)) {
String value = parsePlaceHolder(pkg);
if(StringUtils.hasText(value)){
List<String> valueList = Arrays.asList(value.split(","));
for(String base : valueList){
basePackages.add(base);
}
}
}
}
basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
}
private String parsePlaceHolder(String pro) {
if (StringUtils.hasText(pro) && pro.contains(PropertySourcesPlaceholderConfigurer.DEFAULT_PLACEHOLDER_PREFIX)) {
String value = environment.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;
}
}
MapperScanner.java
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
public @interface MapperScanner {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends Annotation> annotationClass() default Annotation.class;
Class<?> markerInterface() default Class.class;
String sqlSessionTemplateRef() default "";
String sqlSessionFactoryRef() default "";
Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;
}
4、使用MapperScanner,占位符扫描配置
@MapperScanner(basePackages = { "${mybatis.mapperScanner.basePackage}" }, sqlSessionFactoryRef = "sqlSessionFactory")
mybatis:
mapperScanner:
basePackage: com.aa.**.mapper,com.bb.**.mapper
关于@MapperScan配置
问题
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): top.yangzefeng.usercenter.user.service.UserService.getById
解决方案
常用配置:
@MapperScan("top.yangzefeng.usercenter.**.mapper")
@MapperScan("com.demo.mapper")
:扫描指定包中的接口@MapperScan("com.demo.*.mapper")
:一个代表任意字符串,但只代表一级包,比如可以扫到com.demo.aaa.mapper,不能扫到com.demo.aaa.bbb.mapper@MapperScan("com.demo.**.mapper")
:两个代表任意个包,比如可以扫到com.demo.aaa.mapper,也可以扫到com.demo.aaa.bbb.mapper
来源:https://blog.csdn.net/u014704612/article/details/106302123


猜你喜欢
- 目录前言简单示例基础操作定时取消关联取消判断取消源码探究构造入手小插曲WaitHandle注册操作取消操作Cancel操作CancelAft
- 有时候,我们需要在线上预览word文档,当然我们可以用NPOI抽出Word中的文字和表格,然后显示到网页上面,但是这样会丢失掉Word中原有
- 由于MediaPlayer占用资源较多,且不支持同时播放多个音频,所以Android还提供了另一个播放音频的类-----SoundPool。
- EasyDL图像分割介绍创建应用1.进入百度AI开放平台打开控制台:2.在左上角打开产品服务列表,找到EasyDL零门槛AI开放平台:3.打
- java中对List分段操作的实例问题:假设A系统查询出来一个很大很大的List,现在B系统想要得到这个List来导出报表,但是B系统部署环
- 问题:使用getServletContext().getRealPath()得到的是临时文件的路径。每次重启服务,这个临时文件的路径还会变更
- 本文实例为大家分享了Android仿京东左侧分类条目效果的具体代码,供大家参考,具体内容如下import android.app.Activ
- 本文实例讲述了Android发送xml数据给服务器的方法。分享给大家供大家参考。具体如下:一、发送xml数据:public static v
- 使用限定符在平板上面大多数时候采用的双页的模式,程序会在左侧列表上显示一个包含子项列表,右侧的面版会显示详细的内容的因为平板具有足够大的屏幕
- 有经验的程序员应该都见过,一个方法坐拥几十上百个参数。方法为何要有参数?因为不同方法间需共享信息。但方法间共享信息的方式不止一种,除了参数列
- 前言:WPF数据绑定对于WPF应用程序来说尤为重要,本文将讲述使用MVVM模式进行数据绑定的四步走用法:具体实例代码如下:public cl
- 前言Kafka是现在非常热门的分布式消息队列,常用于微服务间异步通信,业务解耦等场景。kafka的性能非常强大,但是单个微服务吞吐性能是有上
- 本文为大家讲解了Struts2框架的入门知识,供大家参考,具体内容如下1、Struts2框架介绍Struts2框架是MVC流程框架,适合分层
- 同学们在开发过程中,经常需要查看程序与数据库之间的SQL语句,以便于调试和分析。本文将介绍如何在控制台中显示MyBatis的SQL语句,帮助
- 1.先在build.gradle(Module)下添加引用viewPager2的库implementation 'androidx.
- /// <summary>/// 获取字符串最长的数字/// </summary>/// <param nam
- Android异常详情介绍这种异常我遇到以下两种情况: 1. java.lang.IllegalStateException: No wra
- 1.概述MybatisPlus是国产的第三方插件, 它封装了许多常用的CURDapi,免去了我们写mapper.xml的重复劳动,这里介绍了
- 实现功能权限校验的功能有多种方法,其一使用 * 拦截请求,其二是使用AOP抛异常。 首先用 * 实现未登录时跳转到登录界面的功能。注意这里没
- 本文实例为大家分享了Android实现拼图游戏的具体代码,供大家参考,具体内容如下本人是用 android studio 完成的源码pack