**若項目中使用了@MapperScan註解後,則@Mapper註解不再生效**, 原因是:@MapperScan註解 會執行@Import(MapperScannerRegistrar.class),而MapperScannerRegistrar又會註冊MapperScannerConfigure ...
若項目中使用了@MapperScan註解後,則@Mapper註解不再生效,
原因是:@MapperScan註解 會執行@Import(MapperScannerRegistrar.class),而MapperScannerRegistrar又會註冊MapperScannerConfigurer BEAN,在MapperScannerConfigurer BEAN中會完成基於配置的包目錄掃描註冊所有mapper interface代理BEAN,而@Mapper註解的生效是由org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration.MapperScannerRegistrarNotFoundConfiguration 配置BEAN類執行@Import(AutoConfiguredMapperScannerRegistrar.class),在AutoConfiguredMapperScannerRegistrar中會掃描所有@Mapper註解的mapper interface並註冊為代理BEAN,但在執行@Import(AutoConfiguredMapperScannerRegistrar.class)時有一個前提,那就是@ConditionalOnMissingBean({ MapperFactoryBean.class, MapperScannerConfigurer.class })【即:在沒有MapperFactoryBean 或 MapperScannerConfigurer】時才會執行,由於MapperScannerRegistrarNotFoundConfiguration 是MybatisAutoConfiguration 配置BEAN的子類,所以MapperScannerRegistrarNotFoundConfiguration 會晚於@MapperScan標記的頂級類,故正常情況下一旦使用了@MapperScan註解後,由於MapperScannerConfigurer BEAN已註冊,那麼MapperScannerRegistrarNotFoundConfiguration 上的@Import(AutoConfiguredMapperScannerRegistrar.class)將不會被執行。
另外要實現動態條件註冊Mapper介面,我們只需要在mapper interface上加上@Conditional(...) 條件註解即可,
原理是:不論是@MapperScan 或是@Mapper 最終都是使用ClassPathMapperScanner.scan完成掃描並註冊成BEAN的,而在scan過程中又會支持較多的TypeFilter,以及在確定候選組件時(org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents)又會進行條件判斷(即:org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#isConditionMatch),判斷是否可以跳過(即:org.springframework.context.annotation.ConditionEvaluator#shouldSkip),在shouldSkip方法中會又會判斷是否為Conditional註解,若是則會執行Condition#matches 進行匹配,若返回true則表示符合要求不跳過(即:候選的BEAN),否則跳過,如此即實現了動態條件註冊Mapper介面代理BEAN的功能。