面试官:讲一下Mybatis在SpringBoot中是如何被加载执行的?

本文详细解析了在SpringBoot中Mybatis如何被加载和执行的过程,从预备知识开始,逐步深入到springboot集成mybatis、MybatisAutoConfiguration加载、@Mapper类的加载以及@MapperScan的使用区别。通过源码分析,阐述了Mybatis在SpringBoot应用中的初始化和运行机制。
摘要由CSDN通过智能技术生成

本文主要讲述mybatis在springboot中是如何被加载执行的,由于涉及的内容会比较多,所以这次只会对调用关系及关键代码点进行讲解,为了避免文章太长,读起来昏昏欲睡,一些不影响整体流程的细节就不涉及了。

源码位置https://github.com/wbo112/blogdemo/tree/main/springbootdemo/springboot-mybatis

1、预备知识

  • FactoryBean什么是FactoryBean?我们先看看FactoryBean的源码
//由 BeanFactory 中使用的对象实现的接口,这些对象本身是单个对象的工厂。如果一个 bean 实现了这个接口,它就被用作一个对象暴露的工厂,而不是直接作为一个将暴露自己的 bean 实例。
//注意:实现此接口的 bean 不能用作普通 bean。 FactoryBean 以 bean 样式定义,但为 bean 引用公开的对象 (getObject()) 始终是它创建的对象。
//FactoryBeans 可以支持单例和原型,并且可以根据需要懒惰地或在启动时急切地创建对象。 SmartFactoryBean 接口允许公开更细粒度的行为元数据。
//该接口在框架本身中被大量使用,例如用于 AOP org.springframework.aop.framework.ProxyFactoryBean 或 org.springframework.jndi.JndiObjectFactoryBean。它也可以用于自定义组件;然而,这仅适用于基础设施代码。
//FactoryBean 是一个程序化契约。实现不应该依赖于注释驱动的注入或其他反射设施。 getObjectType() getObject() 调用可能会在引导过程的早期到达,甚至在任何后处理器设置之前。如果您需要访问其他 bean,请实现 BeanFactoryAware 并以编程方式获取它们。
//容器只负责管理FactoryBean 实例的生命周期,而不负责管理FactoryBean 创建的对象的生命周期。因此,暴露的 bean 对象(例如 java.io.Closeable.close() 上的 destroy 方法不会被自动调用。相反,FactoryBean 应该实现 DisposableBean 并将任何此类关闭调用委托给底层对象。
//最后,FactoryBean 对象参与包含 BeanFactory 的 bean 创建同步。除了 FactoryBean 本身(或类似的)内部的延迟初始化之外,通常不需要内部同步。
package org.springframework.beans.factory;

import org.springframework.lang.Nullable;

public interface FactoryBean<T> {

	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    //返回真正的beanFacotry中的bean对象
	@Nullable
	T getObject() throws Exception;
    
	//返回真正的beanFacotry中的bean对象的类型
	@Nullable
	Class<?> getObjectType();
    
	//是否单例
	default boolean isSingleton() {
		return true;
	}

}

上面就是FactoryBean的源码了,源码中的注释我都删除掉了。类上的中文注释是翻译的源码上的,方法上的注释是我自己加的。简单来说就是时间这个接口的类是作为对象暴漏的工厂,真正调用getObject()才会得到实际的bean对象。

2、springboot集成mybatis

  • 之前的文章简单说到springboot启动的时候会读取META-INF\spring.factories文件,把key=org.springframework.boot.autoconfigure.EnableAutoConfiguration的字符串作为类名去加载(启动会配合META-INF\spring-autoconfigure-metadata.properties中的内容过滤掉不符合当前场景的)springboot集成mybatis也是这样实现的。

面试官:讲一下Mybatis在SpringBoot中是如何被加载执行的?

  • 是由谁来上面的文件的呢我们的main方法上都会有@SpringBootApplication注解

面试官:讲一下Mybatis在SpringBoot中是如何被加载执行的?

在SpringBootApplication这个上面会有个@EnableAutoConfiguration注解

面试官:讲一下Mybatis在SpringBoot中是如何被加载执行的?

在这个上面会有import注解,参数是AutoConfigurationImportSelector.class。真正读取上面文件的类就是AutoConfigurationImportSelector。

面试官:讲一下Mybatis在SpringBoot中是如何被加载执行的?

AutoConfigurationImportSelector.java

//真正的读取代码是在这里
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//在这里读取META-INF\spring.factories文件中key=org.springframework.boot.autoconfigure.EnableAutoConfiguration的值
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
        //在这里读取META-INF\spring.factories文件中key=org.springframework.boot.autoconfigure.AutoConfigurationImportFilter的值根据META-INF\spring-autoconfigure-metadata.properties进行过滤
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

读取META-INF\spring-autoconfigure-metadata.properties文件是在AutoConfigurationImportSelector的内部类ConfigurationClassFilter的构造方法中,真正的过滤也是在这个内部类中

		ConfigurationClassFilter(ClassLoader classLoader, List<AutoConfigurationImportFilter> filters) {
		//在这里读取的META-INF\spring-autoconfigure-metadata.properties
			this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(classLoader);
			this.filters = filters;
		}
//这个也是ConfigurationClassFilter的方法
List<String> filter(List<String> configurations) {
   long startTime = System.nanoTime();
   String[] candidates = StringUtils.toStringArray(configurations);
   boolean skipped = false;
   for (AutoConfigurationImportFilter filter : this.filters) {
   	//执行过滤
      boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
      for (int i = 0; i < match.length; i++) {
         if (!match[i]) {
            candidates[i] = null;
            skipped = true;
         }
      }
   }
     + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
   }
   return result;
}

默认的过滤器是有3个,是在这里

面试官:讲一下Mybatis在SpringBoot中是如何被加载执行的?

在读取过程中就会读取mybatis-spring-boot-autoconfigure-2.2.0.jar中的META-INF\spring.factories配置(本文第一个图),加载下面两个类

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

同样的也会用mybatis-spring-boot-autoconfigure-2.2.0.jar中的META-INF\spring-autoconfigure-metadata.properties文件进行过滤。

面试官:讲一下Mybatis在SpringBoot中是如何被加载执行的?

这里的过滤其实就是用类名+.+Conditional*来作为过滤的

org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration.ConditionalOnClass=org.apache.ibatis.session.SqlSessionFactory,org.mybatis.spring.SqlSessionFactoryBean
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration.ConditionalOnSingleCandidate=javax.sql.DataSource

比如

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值