@MapperScan配置在@Configuration注解的类上会导入MapperScannerRegistrar类。

而MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,可以向BeanDefinitionRegistry注册BeanDefinition。

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

  private ResourceLoader resourceLoader;

  @Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(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));
}
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
} }

从上述源码可以看到MapperScannerRegistrar的registerBeanDefinitions,从mapperScan注解获取到要扫描的包,将扫描路径提交给ClassPathMapperScanner的doScan方法。

ClassPathMapperScanner继承于ClassPathBeanDefinitionScanner,并覆盖doScan方法,通过父类获取到basePackages路径下的类的beanDefinition,然后修改beanDefinition的beanClass为MapperFactoryBean。

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {

  @Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
} return beanDefinitions;
} private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition(); if (logger.isDebugEnabled()) {
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + definition.getBeanClassName() + "' mapperInterface");
} //修改构造方法参数为mapper的class
definition.getConstructorArgumentValues()
.addGenericArgumentValue(definition.getBeanClassName());
//修改beanClass为mapperFactoryBean
definition.setBeanClass(this.mapperFactoryBean.getClass()); definition.getPropertyValues().add("addToConfig", this.addToConfig); //注入sqlSessionFactory/sqlSessionTemplate
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
} if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
} if (!explicitFactoryUsed) {
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
} @Override
//覆盖父类的isCandidateComponent,判断bean为接口且独立
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
} }

最后通过BeanFactory实例化MapperFactoryBean时,因为MapperFactoryBean实现了FactoryBean,会调用getObject生成bean,注册到beanFactory。

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {

  private Class<T> mapperInterface;

  private boolean addToConfig = true;

  public MapperFactoryBean() {
//intentionally empty
} public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
} @Override
//将mapper注册到Configuration中
protected void checkDaoConfig() {
super.checkDaoConfig(); notNull(this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
throw new IllegalArgumentException(e);
} finally {
ErrorContext.instance().reset();
}
}
} @Override
//通过SqlSession获取Mapper代理
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
} }

最新文章

  1. Json.net日期格式化
  2. F#之旅1 - Why use F#?为什么要用F#?
  3. WITH AS的含义
  4. 特征的Attribute Only选项
  5. (转)浅谈MD5加密算法中的加盐值(SALT)
  6. Javascript 常用系统内置函数
  7. HDU 2529 Shot (物理数学题)
  8. python实战--Http代理服务器
  9. linux 添加 $path
  10. 前端input选中状态时的蓝框
  11. Xcode6和Xcode5获取app名字
  12. 学DSP(一):开始
  13. Android中目的地Intent的使用
  14. 干货,比较全面的c#.net公共帮助类
  15. linux_软件安装策略和升级策略
  16. XCTF(77777-2)
  17. Beta冲刺NO.1
  18. Metal并行计算以及Metal程序的命令行编译
  19. Codeforces Round #350 (Div. 2) C. Cinema
  20. C# 调用短信接口

热门文章

  1. 慕课网--docker走进第一个javaweb应用
  2. HTTP之User-Agent大全
  3. Pikachu靶场SQL注入刷题记录
  4. 入门大数据---Scala学习
  5. caffe的python接口学习(2)生成solver文件
  6. 前端基础:”天龙八步“细说浏览器输入URL后发生了什么
  7. Spring Security(四) —— 核心过滤器源码分析
  8. Linux下C++动态加载so 调用方法
  9. python数据结构-最全的六种排序
  10. MACOS使用VScode进行C语言编程