mybatis @MapperScan 解析

mybatis @MapperScan 解析MapperScan注解会引入MapperScannerRegistrar,MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar,可以向beanFactory中注册BeanDefinition,具体注入的过程是通过ClassPathMapperScanner实现的。publicvoidregisterBeanDefi…

大家好,又见面了,我是你们的朋友全栈君。

MapperScan 注解会引入 MapperScannerRegistrar,MapperScannerRegistrar 实现了 ImportBeanDefinitionRegistrar,可以向 beanFactory 中 注册 BeanDefinition,具体注入的过程是通过 ClassPathMapperScanner 实现的。

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

    // this check is needed in Spring 3.1
    if (resourceLoader != null) {
      scanner.setResourceLoader(resourceLoader);
    }

    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(BeanUtils.instantiateClass(generatorClass));
    }

    Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
      scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
    }

    scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
    scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));

    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));
  }

获取注解信息设置到 ClassPathMapperScanner 中,其中 annotationClass 是在扫描的时候只有标注了 annotationClass 的类会被加入到 factory 中。markerInterface 设置父接口,如果设置了那么只有这个markerInterface的子类接口再回被加入到 factory 中。具体的设置在 ClassPathMapperScanner 中的 registerFilters 方法中。

public void registerFilters() {
    boolean acceptAllInterfaces = true;

    // if specified, use the given annotation and / or marker interface
    if (this.annotationClass != null) {
      addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
      acceptAllInterfaces = false;
    }

    // override AssignableTypeFilter to ignore matches on the actual marker interface
    if (this.markerInterface != null) {
      addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
        @Override
        protected boolean matchClassName(String className) {
          return false;
        }
      });
      acceptAllInterfaces = false;
    }

    if (acceptAllInterfaces) {
      // default include filter that accepts all classes
      addIncludeFilter(new TypeFilter() {
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
          return true;
        }
      });
    }

    // exclude package-info.java
    addExcludeFilter(new TypeFilter() {
      @Override
      public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        String className = metadataReader.getClassMetadata().getClassName();
        return className.endsWith("package-info");
      }
    });
  }

可以看出在最后排除了 package-info 的 class 类。ClassPathMapperScanner 其他的方法

  @Override
  protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
  }

表示只会扫描 接口interface 不会扫描 class,第二个方法是表示 当前类可以单独实例化。

protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) {
    if (super.checkCandidate(beanName, beanDefinition)) {
      return true;
    } else {
      logger.warn("Skipping MapperFactoryBean with name '" + beanName 
          + "' and '" + beanDefinition.getBeanClassName() + "' mapperInterface"
          + ". Bean already defined with the same name!");
      return false;
    }
  }

调用父类的方法,

protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
		if (!this.registry.containsBeanDefinition(beanName)) {
			return true;
		}
		BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
		BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
		if (originatingDef != null) {
			existingDef = originatingDef;
		}
		if (isCompatible(beanDefinition, existingDef)) {
			return false;
		}
		throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
				"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
				"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
	}

当前类主要的方法是。

private void processBeanDefinitions(Set 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");
  }

  // the mapper interface is the original class of the bean
  // but, the actual class of the bean is MapperFactoryBean
  definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
  definition.setBeanClass(this.mapperFactoryBean.getClass());

  definition.getPropertyValues().add("addToConfig", this.addToConfig);

  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);
  }
}}

对扫描的每一个 interface 进行处理。
设置bean class 是 MapperFactoryBean,设置 构造函数参数当前扫描到的interface 也就是我们写的 mapper 接口interface 作为 MapperFactoryBean 构造函数的参数。设置 MapperFactoryBean 中的 sqlSessionFactory 属性和sqlSessionTemplate属性,最后设置注入属性 AbstractBeanDefinition.AUTOWIRE_BY_TYPE,就是我们在 serviceImpl 中 autowrite mapper 接口。
下面看 MapperFactoryBean ,这个类实现了 spring FactoryBean 接口。
构造函数

public MapperFactoryBean(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

保存我们自己的 mapper 接口。

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();
      }
    }
  }

会被 spring 回调在

public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
        this.checkDaoConfig();

        try {
            this.initDao();
        } catch (Exception var2) {
            throw new BeanInitializationException("Initialization of DAO failed", var2);
        }
    }

在 DaoSupport 中,主要是完成 mapper xml文件的解析或者 mapper 上注解的解析。
主要是看 getObject 方法,这个是 FactoryBean 定义的。真正被注入到容器中的是这个方法获取的 Object

  @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }

来到 configuration 中的getMapper 方法

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

最终来到MapperProxyFactory 中,获取到的是jdk 动态代理的类。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/133676.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 【接口自动化平台搭建】TestNG搭建接口自动化(一)[通俗易懂]

    【接口自动化平台搭建】TestNG搭建接口自动化(一)[通俗易懂]接口自动化平台搭建,TestNG框架下如何进行测试结果的定制化收集。

    2025年6月12日
    8
  • vs2019配置opengl环境_vs2010配置opengl

    vs2019配置opengl环境_vs2010配置opengl这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML图表FLowchart流程图导出与导入导出导入欢迎使用Markdown编辑器你好!这是你第一次使用Markdown编辑器所展示的欢迎页。如果你想学习如何使用Mar

    2025年7月31日
    4
  • Hadoop生态系统简介

    Hadoop生态系统简介Hadoop生态系统主要包括:Hive、HBase、Pig、Sqoop、Flume、ZooKeeper、Mahout、Spark、Storm、Shark、Phoenix、Tez、Ambari。Hive:用于Hadoop的一个数据仓库系统,它提供了类似于SQL的查询语言,通过使用该语言可以方便地进行数据汇总,特定查询以及分析存放在Hadoop兼容文件系统中的大数据。HBase:一种分布的、可

    2022年5月19日
    40
  • GitHub Universe 2020 强势登陆,GitCode 直播已上线

    GitHub Universe 2020 强势登陆,GitCode 直播已上线什么是GitHubUniverse?GitHubUniverse是GitHub的年度选框产品和社区活动,聚集了构建全球最重要技术的GitHub产品专家,软件领导者和企业团队。GitHub的全球互联社区有机会聚在一起,分享最佳实践,互相学习,并了解GitHub的最新产品和功能。谁应该参加GitHubUniverse?开发人员:会议议题专为运行各种规模项目的开源贡献者和维护者以及希望了解最新软件工具,技术和最佳实践的开发人员而设计。通过深入研究Codespaces,Kubernetes部署

    2022年7月16日
    20
  • out of memory解决方法(python慢的原因)

    折腾了一整天又换电脑又重装系统重装各种软件插件 最后发现outofmemory只是因为少写了一行代码 内心的崩溃无法用语言形容 虽然本来是乌龙一场但是这个过程中解决问题get一些新技能 也不能说完全没有收获【一个大写的心理安慰】开始我的4G小笔记本outofmemory之后,我换了一个32G内存的电脑 各种重装系统折腾半天好不容易都装好了程序可

    2022年4月15日
    173
  • gradle command not found

    gradle command not found

    2021年9月14日
    86

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号