欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MyBatis Plus插件机制与执行流程原理分析

程序员文章站 2022-04-12 21:31:04
...

【1】MyBatis Plus插件

MyBatis Plus提供了分页插件PaginationInterceptor、执行分析插件SqlExplainInterceptor、性能分析插件PerformanceInterceptor以及乐观锁插件OptimisticLockerInterceptor。

Mybatis 通过插件 (Interceptor) 可以做到拦截四大对象相关方法的执行 ,根据需求完成相关数据的动态改变。

四大对象是:

  • Executor
  • StatementHandler
  • ParameterHandler
  • ResultSetHandler

四大对象的每个对象在创建时,都会执行interceptorChain.pluginAll(),会经过每个插件对象的 plugin()方法,目的是为当前的四大对象创建代理。代理对象就可以拦截到四大对象相关方法的执行,因为要执行四大对象的方法需要经过代理 。

① xml下插件的配置

如下所示:

<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
	<!-- 数据源 -->
	<property name="dataSource" ref="dataSource"></property>
	<property name="configLocation" value="classpath:mybatis-config.xml"></property>
	<!-- 别名处理 -->
	<property name="typeAliasesPackage" value="com.jane.mp.beans"></property>
	<!-- 注入全局MP策略配置 -->
	<property name="globalConfig" ref="globalConfiguration"></property>
	<!-- 插件注册 -->
	<property name="plugins">
		<list>
			<!-- 注册分页插件 -->
			<bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
			<!-- 注册执行分析插件 -->
			<bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
				<property name="stopProceed" value="true"></property>
			</bean>
			<!-- 注册性能分析插件 -->
			<bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor">
				<property name="format" value="true"></property>
				<!-- <property name="maxTime" value="5"></property> -->
			</bean>
			<!-- 注册乐观锁插件 -->
			<bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor">
			</bean>
		</list>
	</property>
</bean>

② springboot**册插件

这里以分页插件为例:

@Bean
 public PaginationInterceptor paginationInterceptor() {
     PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
     // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
     // paginationInterceptor.setOverflow(false);
     // 设置最大单页限制数量,默认 500 条,-1 不受限制
     // paginationInterceptor.setLimit(500);
     // 开启 count 的 join 优化,只针对部分 left join
     paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
     return paginationInterceptor;
 }

③ SqlExplainInterceptor

SQL执行分析拦截器,全类名是com.baomidou.mybatisplus.plugins.SqlExplainInterceptor,只支持 MySQL5.6.3以上版本。

该插件的作用是分析 DELETE UPDATE语句 ,防止小白或者恶意进行DELETE UPDATE全表操作,不建议在生产环境中使用会造成性能下降,

在插件的底层通过SQL语句分析命令 Explain 分析当前的 SQL语句,根据结果集中的 Extra列来断定当前是否全表操作。

④ 性能分析插件

性能分析拦截器,全类名是com.baomidou.mybatisplus.plugins.PerformanceInterceptor,用于输出每条 SQL 语句及其执行时间。SQL性能执行分析 ,开发环境使用 超过指定时间,停止运行。

⑤ 乐观锁插件

全类名是com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor。如果想实现如下需求 : 当要更新一条记录的时候,希望这条记录没有被别人更新,就可以使用该插件进行判断。

乐观锁的实现原理(@Version 用于注解实体字段,必须要有) :

  • 取出记录时,获取当前 version
  • 更新时,带上这个version
  • 执行更新时,set version = yourVersion+1 where version = yourVersion
  • 如果 version不对,就更新失败

【2】获取sqlSessionFactoryBean

如下图所示,在系统启动时会初始化定义的bean。DefaultListableBeanFactory.preInstantiateSingletons方法中会从beanDefinitionNames中获取bean name然后依次创建。

这里可以看到RootBeanDefinition是com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean
MyBatis Plus插件机制与执行流程原理分析

① 获取bean的过程中bean属性

如下所示,在getBean过程中可以看到bean的属性:
MyBatis Plus插件机制与执行流程原理分析

② createBean

第一次获取bean的时候会走到AbstractAutowireCapableBeanFactory.createBean进行bean的创建。

 /**
 创建一个bean实例,为bean实例设置属性值,调用post-processors-bean后置处理器
 */
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
//...暂时忽略其他代码
	try {
// 这里会首先触发BeanPostProcessors ,如果这里能获取到bean则直接返回,不再走doCreateBean
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}
//...暂时忽略其他代码

//如果上面没有获取到bean,则会走doCreateBean--这也是创建bean的核心过程
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
//...暂时忽略其他代码
	return beanInstance;
}

在AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation中就会分别执行bean后置处理器的前置和后置方法。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
	Object bean = null;
	if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
		// Make sure bean class is actually resolved at this point.
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			Class<?> targetType = determineTargetType(beanName, mbd);
			if (targetType != null) {
				bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
				if (bean != null) {
					bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
				}
			}
		}
		mbd.beforeInstantiationResolved = (bean != null);
	}
	return bean;
}

执行后置处理器的前置方法如下所示:
MyBatis Plus插件机制与执行流程原理分析

③ doCreateBean

AbstractAutowireCapableBeanFactory.doCreateBean是创建bean的核心方法,这会为bean属性赋值并会触发bean后置处理器、InitializingBean以及自定init方法等。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
	throws BeanCreationException {

// Instantiate the bean.--实例化bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
	instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//获取bean的包装对象-这里很重要
	instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;

// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
	if (!mbd.postProcessed) {
		try {
//调用MergedBeanDefinitionPostProcessors的postProcessMergedBeanDefinition方法
			applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Post-processing of merged bean definition failed", ex);
		}
		mbd.postProcessed = true;
	}
}
//...
//这里暂时忽略其他代码

// Initialize the bean instance.--初始化bean实例
Object exposedObject = bean;
try {
//如下方法很重要
	populateBean(beanName, mbd, instanceWrapper);
	if (exposedObject != null) {
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
}
//...

// Register bean as disposable.
try {
	registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
//...
return exposedObject;
}

④ populateBean

顾名思义,为bean实例属性赋值。

AbstractAutowireCapableBeanFactory.populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
//获取属性值列表
PropertyValues pvs = mbd.getPropertyValues();

//...该种符号表示暂时忽略其他代码

//在为bean属性赋值前,给InstantiationAwareBeanPostProcessors 机会修改bean的状态
//应用场景如支持字段注入
boolean continueWithPropertyPopulation = true;

//循环调用InstantiationAwareBeanPostProcessors 的postProcessAfterInstantiation方法
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
				continueWithPropertyPopulation = false;
				break;
			}
		}
	}
}

if (!continueWithPropertyPopulation) {
	return;
}
//解析autowire注解字段,进行主动注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
		mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
	MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

	// Add property values based on autowire by name if applicable.
	if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
		autowireByName(beanName, mbd, bw, newPvs);
	}

	// Add property values based on autowire by type if applicable.
	if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
		autowireByType(beanName, mbd, bw, newPvs);
	}

	pvs = newPvs;
}

boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

//循环调用InstantiationAwareBeanPostProcessors 的postProcessPropertyValues方法
if (hasInstAwareBpps || needsDepCheck) {
	PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
	if (hasInstAwareBpps) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
				if (pvs == null) {
					return;
				}
			}
		}
	}
	if (needsDepCheck) {
		checkDependencies(beanName, mbd, filteredPds, pvs);
	}
}
//在这里为属性赋值,会进行类型转换,这里注意关键词deep copy
//如果是引用类型且bean没有存在,则会进行bean的创建过程
applyPropertyValues(beanName, mbd, bw, pvs);
}

如下图所示在创建sqlSessionFactoryBean过程中会创建其属性globalConfiguration对象:
MyBatis Plus插件机制与执行流程原理分析
如下图所示在创建sqlSessionFactoryBean过程中(从左侧的方法顺序就可以看出来)会创建其属性PaginationInterceptor对象:
MyBatis Plus插件机制与执行流程原理分析
如下图所示在创建sqlSessionFactoryBean过程中(从左侧的方法顺序就可以看出来)会创建其属性SqlExplainInterceptor对象:
MyBatis Plus插件机制与执行流程原理分析
如下图所示在创建sqlSessionFactoryBean过程中(从左侧的方法顺序就可以看出来)会创建其属性PerformanceInterceptor对象:
MyBatis Plus插件机制与执行流程原理分析
如下图所示在创建sqlSessionFactoryBean过程中(从左侧的方法顺序就可以看出来)会创建其属性OptimisticLockerInterceptor对象:
MyBatis Plus插件机制与执行流程原理分析


⑤ initializeBean

AbstractAutowireCapableBeanFactory.initializeBean源码如下:

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
	if (System.getSecurityManager() != null) {
		AccessController.doPrivileged(new PrivilegedAction<Object>() {
			@Override
			public Object run() {
				invokeAwareMethods(beanName, bean);
				return null;
			}
		}, getAccessControlContext());
	}
	else {
	//调用意识/通知方法
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
	//调用bean后置处理器的前置方法
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}
	//调用初始化方法
	try {
		invokeInitMethods(beanName, wrappedBean, mbd);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				(mbd != null ? mbd.getResourceDescription() : null),
				beanName, "Invocation of init method failed", ex);
	}

	if (mbd == null || !mbd.isSynthetic()) {
	//	//调用bean后置处理器的后置方法
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	return wrappedBean;
}

AbstractAutowireCapableBeanFactory.invokeInitMethods方法源码如下:

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
			throws Throwable {

	boolean isInitializingBean = (bean instanceof InitializingBean);
	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
		if (logger.isDebugEnabled()) {
			logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
		}
		//调用InitializingBean.afterPropertiesSet
		if (System.getSecurityManager() != null) {
			try {
				AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
					@Override
					public Object run() throws Exception {
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}
				}, getAccessControlContext());
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			((InitializingBean) bean).afterPropertiesSet();
		}
	}
//调用自定义初始化方法
	if (mbd != null) {
		String initMethodName = mbd.getInitMethodName();
		if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
				!mbd.isExternallyManagedInitMethod(initMethodName)) {
			invokeCustomInitMethod(beanName, bean, mbd);
		}
	}
}

如下图所示,MybatisSqlSessionFactoryBean同样实现了InitializingBean接口。那么我们就需要注意其afterPropertiesSet方法了。
MyBatis Plus插件机制与执行流程原理分析

⑥ MybatisSqlSessionFactoryBean.afterPropertiesSet

如下所示,代码很简短只是创建了sqlSessionFactory。

@Override
public void afterPropertiesSet() throws Exception {
    notNull(dataSource, "Property 'dataSource' is required");
 //sqlSessionFactoryBuilder在populateBean的applyPropertyValues过程中已经存在!
    notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
    state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
        "Property 'configuration' and 'configLocation' can not specified with together");

    this.sqlSessionFactory = buildSqlSessionFactory();
}

进入afterPropertiesSet()方法前MybatisSqlSessionFactoryBean如下所示:
MyBatis Plus插件机制与执行流程原理分析

我们看一下sqlSessionFactory,这是一段很长的过程:

protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
    Configuration configuration;
    // TODO 加载自定义 MybatisXmlConfigBuilder
    MybatisXMLConfigBuilder xmlConfigBuilder = null;
    if (this.configuration != null) {
        configuration = this.configuration;
        if (configuration.getVariables() == null) {
            configuration.setVariables(this.configurationProperties);
        } else if (this.configurationProperties != null) {
            configuration.getVariables().putAll(this.configurationProperties);
        }
    } else if (this.configLocation != null) {
 //通常如果配置了configLocation会从这里创建MybatisXMLConfigBuilder,
 //其构造方法又创建了MybatisConfiguration
        xmlConfigBuilder = new MybatisXMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
        configuration = xmlConfigBuilder.getConfiguration();
    } else {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
        }
        // TODO 使用自定义配置
        configuration = new MybatisConfiguration();
        if (this.configurationProperties != null) {
            configuration.setVariables(this.configurationProperties);
        }
    }

    if (this.objectFactory != null) {
        configuration.setObjectFactory(this.objectFactory);
    }

    if (this.objectWrapperFactory != null) {
        configuration.setObjectWrapperFactory(this.objectWrapperFactory);
    }

    if (this.vfs != null) {
        configuration.setVfsImpl(this.vfs);
    }

    if (hasLength(this.typeAliasesPackage)) {
        // TODO 支持自定义通配符
        String[] typeAliasPackageArray;
        if (typeAliasesPackage.contains("*") && !typeAliasesPackage.contains(",")
            && !typeAliasesPackage.contains(";")) {
            typeAliasPackageArray = PackageHelper.convertTypeAliasesPackage(typeAliasesPackage);
        } else {
            typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        }
        if (typeAliasPackageArray == null) {
            throw new MybatisPlusException("not find typeAliasesPackage:" + typeAliasesPackage);
        }
        for (String packageToScan : typeAliasPackageArray) {
            configuration.getTypeAliasRegistry().registerAliases(packageToScan,
                typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");
            }
        }
    }

    // TODO 自定义枚举类扫描处理
    if (hasLength(this.typeEnumsPackage)) {
        Set<Class> classes = null;
        if (typeEnumsPackage.contains("*") && !typeEnumsPackage.contains(",")
            && !typeEnumsPackage.contains(";")) {
            classes = PackageHelper.scanTypePackage(typeEnumsPackage);
        } else {
            String[] typeEnumsPackageArray = tokenizeToStringArray(this.typeEnumsPackage,
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
            if (typeEnumsPackageArray == null) {
                throw new MybatisPlusException("not find typeEnumsPackage:" + typeEnumsPackage);
            }
            classes = new HashSet<Class>();
            for (String typePackage : typeEnumsPackageArray) {
                classes.addAll(PackageHelper.scanTypePackage(typePackage));
            }
        }
        // 取得类型转换注册器
        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        for (Class cls : classes) {
            if (cls.isEnum()) {
                if (IEnum.class.isAssignableFrom(cls)) {
                    typeHandlerRegistry.register(cls.getName(), com.baomidou.mybatisplus.handlers.EnumTypeHandler.class.getCanonicalName());
                } else {
                    // 使用原生 EnumOrdinalTypeHandler
                    typeHandlerRegistry.register(cls.getName(), org.apache.ibatis.type.EnumOrdinalTypeHandler.class.getCanonicalName());
                }
            }
        }
    }

    if (!isEmpty(this.typeAliases)) {
        for (Class<?> typeAlias : this.typeAliases) {
            configuration.getTypeAliasRegistry().registerAlias(typeAlias);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Registered type alias: '" + typeAlias + "'");
            }
        }
    }

    if (!isEmpty(this.plugins)) {
        for (Interceptor plugin : this.plugins) {
            configuration.addInterceptor(plugin);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Registered plugin: '" + plugin + "'");
            }
        }
    }

    if (hasLength(this.typeHandlersPackage)) {
        String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
            ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        for (String packageToScan : typeHandlersPackageArray) {
            configuration.getTypeHandlerRegistry().register(packageToScan);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Scanned package: '" + packageToScan + "' for type handlers");
            }
        }
    }

    if (!isEmpty(this.typeHandlers)) {
        for (TypeHandler<?> typeHandler : this.typeHandlers) {
            configuration.getTypeHandlerRegistry().register(typeHandler);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Registered type handler: '" + typeHandler + "'");
            }
        }
    }

    if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls
        try {
            configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
        } catch (SQLException e) {
            throw new NestedIOException("Failed getting a databaseId", e);
        }
    }

    if (this.cache != null) {
        configuration.addCache(this.cache);
    }

    if (xmlConfigBuilder != null) {
        try {
            xmlConfigBuilder.parse();

            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
            }
        } catch (Exception ex) {
            throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
        } finally {
            ErrorContext.instance().reset();
        }
    }

    if (this.transactionFactory == null) {
        this.transactionFactory = new SpringManagedTransactionFactory();
    }

    configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));
    // 设置元数据相关
    GlobalConfigUtils.setMetaData(dataSource, globalConfig);
    SqlSessionFactory sqlSessionFactory = this.sqlSessionFactoryBuilder.build(configuration);
    // TODO SqlRunner
    SqlRunner.FACTORY = sqlSessionFactory;
    // TODO 缓存 sqlSessionFactory
    globalConfig.setSqlSessionFactory(sqlSessionFactory);
    // TODO 设置全局参数属性
    globalConfig.signGlobalConfig(sqlSessionFactory);
    if (!isEmpty(this.mapperLocations)) {
        if (globalConfig.isRefresh()) {
            //TODO 设置自动刷新配置 减少配置
            new MybatisMapperRefresh(this.mapperLocations, sqlSessionFactory, 2,
                2, true);
        }
        for (Resource mapperLocation : this.mapperLocations) {
            if (mapperLocation == null) {
                continue;
            }

            try {
                // TODO  这里也换了噢噢噢噢
                XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
                    configuration, mapperLocation.toString(), configuration.getSqlFragments());
                xmlMapperBuilder.parse();
            } catch (Exception e) {
                throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
            } finally {
                ErrorContext.instance().reset();
            }

            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
            }
        }
    } else {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
        }
    }
    return sqlSessionFactory;
}

上面代码主要做了如下事情:

  • 获取MybatisXMLConfigBuilder对象
  • 获取Configuration对象-MybatisConfiguration
  • 配置对象Configuration添加插件configuration.addInterceptor(plugin);
  • xmlConfigBuilder.parse()对configuration做进一步处理
  • 获取SpringManagedTransactionFactory用来创建SpringManagedTransaction
  • 获取一个DefaultSqlSessionFactory实例对象
  • globalConfig.setSqlSessionFactory(sqlSessionFactory)中会创建MybatisSqlSessionTemplate
  • 解析mapperLocation对应的一个个mapper配置文件,使用助手builderAssistant的addMappedStatement方法将一个个结点添加配置对象中
  • 其他属性设置等等

也就是说,在MybatisSqlSessionFactoryBean.afterPropertiesSet方法执行结束后,SqlSessionFactory、SqlSessionTemplate、Configuration等都已存在!

【3】查询执行流程分析

示例代码如下:

List<Employee > emps = employeeMapper.selectPage(page, null);

如下图所示,此时我们获取到的employeeMapper其实是个代理对象:
MyBatis Plus插件机制与执行流程原理分析
MyBatis Plus插件机制与执行流程原理分析