SpringBoot實現(xiàn)MapperScan添加動態(tài)配置(占位符)
MapperScan添加動態(tài)配置(占位符)
在對Mybatis自動掃描配置中,使用注解配置時,@MapperScan中的配置,通常配置如下:
@MapperScan(basePackages = {"com.aa.**.mapper","com.bb.**.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory")
不支持在yml或properties文件中動態(tài)配置。因為MapperScan注解功能的實現(xiàn)類MapperScannerRegistrar實現(xiàn)的是ImportBeanDefinitionRegistrar。在對@Configuration注解標記的類配置時,實現(xiàn)占位符功能的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));
從上面代碼中可以看出
為了拓展支持占位符動態(tài)配置,只需把basePackages的加載改寫即可。
1、參考MapperScannerRegistrard,實現(xiàn) ImportBeanDefinitionRegistrar和ResourceLoaderAware兩個接口
2、為了動態(tài)讀取配置文件信息,需要引入Environment,所以實現(xiàn)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
關(guān)于@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
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java圖形界面之JFrame,JLabel,JButton詳解
這篇文章主要介紹了Java圖形界面之JFrame、JLabel、JButton詳解,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04解決springboot bean中大寫的字段返回變成小寫的問題
這篇文章主要介紹了解決springboot bean中大寫的字段返回變成小寫的問題,具有很好的參考價值希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01Struts2源碼分析之ParametersInterceptor攔截器
這篇文章主要介紹了Struts2源碼分析之ParametersInterceptor攔截器,ParametersInterceptor攔截器其主要功能是把ActionContext中的請求參數(shù)設(shè)置到ValueStack中,,需要的朋友可以參考下2019-06-06SpringBoot?LocalDateTime格式轉(zhuǎn)換方案詳解(前端入?yún)?
這篇文章主要介紹了SpringBoot?LocalDateTime格式轉(zhuǎn)換(前端入?yún)?,本文用示例介紹SpringBoot全局格式配置,將前端傳過來的時間自動轉(zhuǎn)化為LocalDateTime,需要的朋友可以參考下2023-04-04Java 實現(xiàn)多線程切換等待喚醒交替打印奇偶數(shù)
這篇文章主要介紹了Java 實現(xiàn)多線程切換等待喚醒交替打印奇偶數(shù) ,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-05-05