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

本文详细解析了Mybatis在SpringBoot中的加载执行过程,从FactoryBean的概念出发,探讨了SpringBoot如何通过@EnableAutoConfiguration注解读取META-INF/spring.factories文件加载Mybatis。接着,介绍了SpringBoot如何通过AutoConfigurationImportSelector和AutoConfigurationImportFilter进行配置过滤。重点分析了MybatisAutoConfiguration类,包括条件判断、Bean的创建与注册,以及@Mapper类的扫描和加载过程。最后,讨论了@MapperScan注解的作用和区别。
摘要由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也是这样实现的。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

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

编辑切换为居中

添加图片注释,不超过 140 字(可选)

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

编辑切换为居中

添加图片注释,不超过 140 字(可选)

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

编辑切换为居中

添加图片注释,不超过 140 字(可选)

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个,是在这里

编辑切换为居中

添加图片注释,不超过 140 字(可选)

在读取过程中就会读取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文件进行过滤。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

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

 

                
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值